home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / Documentation / hAWK User’s Manual < prev    next >
Text File  |  1997-05-26  |  183KB  |  3,614 lines

  1. *********************  hAWK User’s Manual  *********************
  2. Copyright © 1991 the Free Software Foundation, Inc. You can redistribute or modify
  3. this file under the terms of the GNU General Public License as published by
  4. the Free Software Foundation (see the file “COPYING hAWK”).
  5. font: Geneva 10. Four spaces per tab.
  6.  
  7. hAWK is NOT a stand–alone application: it must be called by some other application.
  8. Interaction between hAWK and the calling application will vary according to how
  9. well the calling application supports text documents. However, virtually any
  10. (C-based) application can add the ability to call hAWK. For details, see
  11. “Calling hAWK from your application” near the end of this manual.
  12.  
  13. Applications which support calling hAWK (add yours to the list!):
  14. Minimal App (included, with source code)
  15. EnterAct, RFEdit, EnterAct Lite
  16.  
  17. You can read this document with any programmer’s editor (you may not see the 4
  18. pictures - they’re not that critical). You’ll need an editor to view the results of a
  19. program run if you use Minimal App to call hAWK, since Minimal App does not do
  20. anything with text files, and you’ll find that Minimal App, with its minimal level of
  21. support, has limited program input options. In fact, calling hAWK through Minimal
  22. App shows what hAWK would look like if it were repackaged as a stand–alone
  23. application. See “Calling hAWK through Minimal App” (in the “Advanced topics”
  24. chapter) for tips on using Minimal App with an editor to run hAWK programs.
  25.  
  26. Major topics are marked with MPW-compatible marks, available in many editors by
  27. holding down the <Option> or <Command> key while clicking in the window’s title bar.
  28. You can jump to a section heading by selecting the heading in the table of contents and
  29. using the editor’s “Enter Selection”/“Find Again” commands. The “Active index” at
  30. the end of this manual is suitable for on-line use, consisting of line numbers rather
  31. than page numbers; to jump to the line for a reference in the index, select the
  32. corresponding line number and use the editor’s “Go to” command.
  33.  
  34. If you change the content of this manual you will throw off the Active index, and will
  35. lose the marker locations also if the editor doesn’t manage MPW–compatible marks.
  36. However, feel free to add or delete markers, or change the font.
  37.  
  38. Why bother to learn hAWK?
  39. •    Many editing and formatting problems that crop up in the life of a C programmer
  40. can be solved with a simple hAWK program. Now you have a choice—grind out a
  41. series of mechanically–repeated key strokes, or dash off an elegant little program.
  42. And when it comes time to solve a problem, a typical hAWK program can be run
  43. with two mouse picks and a press of the <Return> key (or even a command line).
  44. • On the Mac alone, there are versions of AWK that run under the MPW shell, under
  45. A/UX, and now with hAWK there is a version that’s handy to use in conjunction with
  46. THINK C. Never mind all the DOS and Unix implementations—even on the Mac, hAWK
  47. is a widely–used language. You’re not learning a white elephant, here.
  48. •    Need to prototype a “little” language? Try out an algorithm? Looking for an
  49. introduction to C that comes with air bags? This is it. For a sampling of what hAWK
  50. can do, see “About the supplied programs” below.
  51.  
  52. Contents
  53. -----------
  54. Introduction
  55. Installing hAWK
  56. Where to go from here
  57. About hAWK
  58.     From AWK to gAWK to hAWK
  59.     What’s missing
  60.     What’s new
  61.     The calling application
  62. A typical hAWK run
  63. Running hAWK programs
  64.     The setup dialog
  65.     Concurrent and immediate modes
  66.     Selecting your program
  67.     Selecting input for a program
  68.     Setting variables
  69.     Library files
  70.     Showing the results
  71.     Saving the setup for a program
  72.     Cancelling a run
  73. Standard input and output
  74. About the supplied programs
  75. hAWK program structure
  76.     From start to finish
  77.     Grouping and breaking lines
  78. The command line and ARGV[]
  79. Variables and constants
  80.     Variable names and types
  81.     Constants
  82.     Record and field variables
  83.     Built–in variables
  84.     Local variables in functions
  85.     Setting variables on the command line
  86.     Conversion between numbers and strings
  87.     Arrays
  88. Patterns
  89.     Patterns and actions
  90.     BEGIN and END
  91.     Expressions as patterns
  92.     String-matching patterns
  93.     Regular expressions
  94.     Compound patterns
  95.     Range patterns
  96.     Summary of patterns
  97. Actions
  98.     Introduction
  99.     A preview of “print’
  100.     Expression operators
  101.     Built–in numeric functions
  102.     Built–in string and file functions
  103.     Control-flow statements
  104.     Empty statements
  105. User-defined functions
  106. Output
  107.     The “print” statement
  108.     The “printf” statement
  109.     Output into files
  110.     Closing files
  111. Input
  112.     FS, the input field separator
  113.     RS, the input record separator
  114.     The “getline” function
  115. The “hAWK” function
  116. Advanced topics
  117.     Other ways of specifying input files
  118.     Beyond input records
  119.     Calling hAWK through Minimal App
  120. Calling hAWK from your application
  121.     What and how
  122.     Getting started
  123.     Add two calls in your code
  124.     A minimal version
  125.     Callbacks, and showing results
  126.     Using a command line
  127. Modifying hAWK
  128.     Introduction
  129.     hAWK THINK C project
  130.     Source
  131.     Libraries
  132. Active index
  133.  
  134.  
  135. -------------
  136.     Introduction
  137. -------------
  138. hAWK is AWK adapted for the Macintosh, a small programming language which is
  139. well-suited to jobs involving text manipulation and pattern recognition. hAWK
  140. is not a stand-alone application, but is rather a CODE resource with a specific simple
  141. calling interface (called a "Drag_on Module"), and it is invoked by selecting "hAWK"
  142. from a menu in an application that can call Drag_on Modules.
  143.  
  144. This manual will explain in more detail what hAWK is, and show you how to run hAWK
  145. programs. There are many useful programs suppled in the "hAWK programs" folder,
  146. each with complete instructions at the top so you can try them out as you go along; they
  147. range from very simple to rather complex, general purpose to very special purpose,
  148. and illustrate the wide range of hAWK’s abilities, from counting lines in a file to
  149. cross–referencing your C source. The chapter below entitled “About the supplied
  150. programs” provides an overview of the programs in the “hAWK programs” folder.
  151. These programs are not just useful as “examples to learn from”—they are, for the
  152. most part, nontrivial, and supply real answers to the daily problems of a C
  153. programmer.
  154.  
  155. What is hAWK really? hAWK is what C could be if you weren't in a hurry. hAWK
  156. programs are relatively small, look rather like C code, and rely on powerful built-in
  157. capabilities and commands—capabilities like automatic reading of input files on a
  158. line-by-line basis, commands such as "gsub" which is, just on its own, as powerful
  159. as Grep. The focus is on text, but the text can be just about anything—the sample
  160. program “$Print_MENU_Resource”, for example, will take the hex representation
  161. of a MENU resource as retrieved by Read Resource and format it to be human–readable.
  162.  
  163. The primary difference between hAWK and other versions of AWK lies in the method of
  164. running programs; hAWK’s setup dialog allows you to run programs with just a few
  165. mouse clicks, with typing needed only if you wish to assign initial values to variables
  166. before a run. This is mainly because hAWK can take advantage of the window and file
  167. handling abilities of the application that is used to call it, to offer the options of taking
  168. input for the hAWK program from text in the front window of the calling application,
  169. or from the list of files selected for multi–file operations. These generalised input
  170. specifications, “whatever’s in the front window” and “whatever’s selected for
  171. multi–file operations”, eliminate the need to type in a list of file names for a program
  172. to use as input. And since each program can remember the general input method you
  173. have selected for it, repeated runs of a program are reduced to: bringing the input to
  174. hAWK’s attention, either by bringing a text file to the front or by selecting files for
  175. multi–file searching; and then running the program with three mouse clicks. This all
  176. makes hAWK as easy to run as a macro language, and since AWK is a widely–used,
  177. full–featured programming language you should find it well worth the effort of
  178. learning.
  179.  
  180. Although running hAWK with the setup dialog is normally the easiest way, hAWK
  181. can also be called with an old-fashioned command line. You can’t pass any frontmost
  182. text to hAWK this way (since the frontmost text will be the command line), but
  183. you can typically specify all files selected for multi-file operations as input, or
  184. specify one or more input files using full path names. If you want to implement an
  185. application that supports calling hAWK via a command line, please see the section
  186. "Using a command line" in the "Calling hAWK from your application" chapter below.
  187. If you just want to use the command line approach, see the documentation supplied
  188. with your application that calls hAWK for the details on how to do it.
  189.  
  190. ---------------
  191.     Installing hAWK
  192. ---------------
  193. If you can read this, then you’ve installed hAWK, since it is being shipped in
  194. compressed form these days. As a reminder, hAWK should be inside your
  195. "Drag_on Modules" folder, and this folder should be in the same folder that
  196. contains the calling application, at the same level. The "hAWK programs" folder
  197. should also be in the "Drag_on Modules" folder, and this manual can go anywhere.
  198.  
  199. To verify that hAWK has been installed, start up an application that can call hAWK
  200. and then check the menus; you should see “hAWK” as one of the items. Select “hAWK”,
  201. and the setup dialog for hAWK will appear. Venture on ahead fearlessly if you like,
  202. armed with the magic incantation that holding down the <Command> key while typing
  203. a <period> will interrupt any running hAWK program.
  204.  
  205. ------------------
  206.     Where to go from here
  207. ------------------
  208. Read straight ahead here until you’ve tried out a few hAWK programs and are comfortable
  209. with the overall approach to running them. The supplied programs in the “hAWK
  210. programs” folder are worth exploring to get a feel for what hAWK can do—and you’ll
  211. likely find that several of them provide answers to problems little or big that you
  212. regularly face. The remainder of this manual delves into the inner workings of hAWK,
  213. necessary reading if you want to write your own hAWK programs (and who could
  214. resist?). If you make use of the markers in this manual for the chapter and
  215. section headings, and the active index at the end listing topics, you’ll be able to browse
  216. around almost as easily as with a printed book.
  217.  
  218. This is a good–sized manual, and if you try to read straight through it at one sitting
  219. you’ll probably hurt your head. Just amble along at a gentle pace, and when ideas or
  220. questions pop up, you’ll find it well worth the effort if you take a moment to write
  221. a one or two–line hAWK program to try the notion out. Running a hAWK program
  222. takes just a few mouse clicks. The easiest way is with “$RunClip” (see chapter H).
  223.  
  224. You can, if you wish, print this manual yourself. Aha, but what about that index, which
  225. lists line numbers rather than page numbers? Thought you might ask that—what you
  226. want, then, is a version of this manual with line numbers added at the beginning of each
  227. line. An ideal job for hAWK!
  228. 1 Use a “Save As” command to save this manual under a different name, such
  229. as “hAWK Manual” (or save it under the same name but in a different folder):
  230. 2 Select “hAWK” from the calling application’s menu, and the setup dialog will appear;
  231. select “$AddLineNumbers” from the “Main program:” popup menu at the top; pick the
  232. “Select input file” option from the “Take input from:” popup, and use the standard
  233. Open dialog that appears to select the copy of this manual that you just created:
  234. 2a Click “Run” and wait a bit....and you’re back in the calling application:
  235. 3    Open the copy of this manual—if you left it on–screen while running hAWK,
  236. choose “Revert” to see the changed version (you can force Revert to be enabled by
  237. typing one character in the window):
  238. 4    Print the result —change the font first, if you like.
  239. 5    Note, to include the pictures you will have to use ResEdit to copy them from the
  240. original manual to your copy of the manual, and use EnterAct to print. They deal with
  241. the setup dialog only, and you shouldn’t miss them much if you don’t bother.
  242.  
  243.  
  244. A very readable description of AWK (excluding the Macintosh variations of hAWK) can
  245. be found in
  246.             "The AWK Programming Language" ,
  247.             Alfred V. Aho, Brian W. Kernighan, Peter J. Weinberger,
  248.             Addison-Wesley, 1988. ISBN 0-201-07981-X.
  249. on the "Languages" or "unix" wall of your favourite bookstore.
  250.  
  251. A more relaxed, though less ambitious, introduction can be found in
  252.             "sed & awk"
  253.             Dale Dougherty
  254.             O’Reilly & Associates, Inc., 1991. ISBN 0-937175-59-5.
  255. The coverage of regular expressions is especially sympathetic.
  256.  
  257. ----------
  258.     About hAWK
  259. ----------
  260.     From AWK to gAWK to hAWK
  261. hAWK is a Macintosh version of AWK, a pattern-recognition and data-manipulation
  262. language that is popular on unix systems. This version of hAWK is a modification of
  263. GAWK, the GNU Project's implementation of the AWK programming language, which
  264. differs in only minor ways from "classic" AWK. "hAWK" will be the name used
  265. below, except where differences from Gawk or AWK need pointing out.
  266.  
  267. AWK has a venerable history, going all the way back to 1977 when messrs Aho,
  268. Weinberger, and Kernighan developed it at Bell Labs to fill in some small holes
  269. in Unix. The idea then was to write one or two–line programs to solve simple
  270. pattern–matching and text or number transforming problems—programs so small
  271. that you wouldn’t even bother to save them, just type them in on the fly, right on
  272. the command line. Over the years, users have pushed the limits of AWK, and many
  273. features have been added (user–definable functions being the nicest), and now
  274. multiple–page AWK programs are commonplace.
  275.  
  276. GAWK is a Unix/IBM version of AWK, developed around 1986 by Paul Rubin and Jay
  277. Fenlason and copyright by the Free Software Foundation. It adds some useful
  278. enhancements to AWK, dealing mostly with files and variables.
  279.  
  280. hAWK is essentially GAWK adjusted for the Macintosh, with the addition of a dialog
  281. interface to take advantage of windows and mice. If you wish to distribute hAWK, by
  282. the way, you should note that it is governed by the Free Software Foundation’s
  283. copyright restrictions (not too horrible) which you can find in the file “COPYING
  284. hAWK” in the source code folder for hAWK.
  285.  
  286.     What’s missing
  287. Pipes are missing. Pipes take a full–fledged shell to run, and most applications aren’t
  288. up to it. Since hAWK is packaged as a CODE resource to be called by any old application,
  289. pipes had to go. Similarly, the “system” command (which allows one to call other shell
  290. commands from within an AWK program) has been dropped.
  291.  
  292.     What’s new
  293. The interface is new. No more command line—most hAWK programs can be run with
  294. just a few mouse clicks, and typing is needed only if you want to set the value of
  295. variables before running the program. (Note a command line is supported though.)
  296.  
  297. There are seven new built–in string functions, “lookup”, “sort”, “time”, “prompt”,
  298. “progress”, “getclip”, and “putclip”, described in “Built–in string and file functions” in the
  299. “Actions” chapter. Some new file and directory functions are also described there.
  300.  
  301. The “lookup” function returns the type of a C term as an integer code (#define = 1,
  302. variable = 2, etc), useful when doing cross-referencing. It relies on the calling
  303. application for this diagnosis, so hAWK programs that use “lookup” should be called
  304. only through applications which support it (Minimal App doesn’t).
  305.  
  306. The “sort” function is provided to (mostly) make up for the lack of a shell sorting
  307. function. It’s fast, and can do ASCII, numeric, or dictionary–order sorting of an array,
  308. in forward or reverse order.
  309.  
  310. The “time” function produces the current date and time, to the second.
  311.  
  312. The “prompt” function prompts you with a dialog to enter some text, and returns what
  313. you enter as a string, as in
  314.         X = prompt("Please enter a value for X:")
  315.  
  316. The “progress” function allows you to show (and update) a message while a program is
  317. running.
  318.  
  319. The “getclip” function returns a string holding the calling application’s current (up to
  320. the second) private clipboard. This can be used to pass instructions or data to a hAWK
  321. function while it is running concurrently with your application (more on this,
  322. needless to say, below). Similarly, putclip puts a new string of text on the clip.
  323.  
  324. As a partial replacement for the “system” command, any hAWK program can call any
  325. other hAWK program as a “subroutine”, via the “hAWK()” function. Using this
  326. function, a program can generate a special-purpose program and immediately
  327. execute it (eg $MFS_SuperReplace), or selectively execute a series of programs (eg
  328. $Chain). It also allows you to type in and run programs without saving them first (eg
  329. $RunClip). This function is decribed in its own chapter, “The hAWK function”.
  330.  
  331. Three built–in variables have been added; RUNERR, STDPATH, and TIME. See “Built-in
  332. variables” in the “Variables and constants” chapter for details.
  333.  
  334. hAWK uses the concept of standard input, output, and error, but strictly in the
  335. form of files with the fixed names $tempStdIn, $tempStdOut, and $tempStdErr.
  336. These files are created and written to as needed, and can be found in the same
  337. folder that contains your “Drag_on Modules” folder after you’ ve begun running
  338. hAWK programs. These are temporary files, and will normally be overwritten
  339. by each hAWK program run.
  340.  
  341. The regular expressions implemented in hAWK are full regular expressions, with the
  342. ability to tag subexpressions, match word boundaries, ignore case, and deal with
  343. multi–line strings. Just about anywhere else in this world, you’ll find either full
  344. regular expressions or the ability to tag subexpressions, but not both. One minute you
  345. want the “or” operator, the next minute you want to tag something—it gets rather
  346. frustrating. There is absolutely no good reason not to allow both together, so in hAWK
  347. you’ve got them. Speaking of gripes, most Grep’s will limit you to a single line—that’s
  348. not just frustrating, it’s downright crippling. (By the way, another major
  349. improvement over Grep is that in AWK/hAWK your regular expression can be the
  350. string resulting from the evaluation of one or more variables, eg
  351.     if (no_plus_or_minus)
  352.         integer_pattern = digits; # digits == "[0123456789]+"
  353.     else
  354.         integer_pattern = plus_or_minus digits; # plus_or_minus == "[+-]?"
  355. —and a pleasant side–effect is that regular expressions can be very readable if you want.)
  356. For the details, see “Regular expressions” in the “Patterns” chapter.
  357.  
  358. If the calling application supports the notion, your hAWK programs will by default
  359. run concurrently with your calling app. This means you start up the hAWK program,
  360. and then go back to working in your application (or background it and work somewhere
  361. else) until the hAWK program is done. The “prompt” and “progress” functions are
  362. non-functional in this concurrent mode, so you can run programs in the “immediate”
  363. mode, which supports “prompt” and “progress” by holding down the
  364. <Shift> key while selecting “hAWK” from the calling application’s menu. In
  365. immediate mode, you will be locked out of the calling application until the hAWK
  366. program ends. Programs will run more slowly in concurrent mode (the speed
  367. drop being slightly greater if you put the calling application in the background),
  368. but this is usually more than compensated for by being able to carry on with other
  369. things, rather than just sit there watching the watch cursor. The running hAWK program
  370. usually doesn’t affect application performance very much. For more about this,
  371. see “Concurrent and immediate modes” in the “Running hAWK programs” chapter.
  372.  
  373.     The calling application
  374. Any C-based application can call hAWK and other Drag_on Modules, as the source
  375. code for Minimal App demonstrates. The level of interaction between hAWK and
  376. the calling application is up to the author of the calling application, and can vary
  377. more or less according to the following table:
  378.  
  379. Level                Support for interactive features
  380. ----                -----------------------
  381. minimal            (none; no result showing, input options limited to one specific file)
  382. basic text            pass front text window as input option, show stdout after a run
  383. full text            basic text, and pass list of selected files as input option
  384. full                    full text, diagnose the type of a C code term, pass the clipboard
  385.  
  386. If the application you are using provides only minimal support, then some extra
  387. manual steps are needed to persuade a hAWK program to take input from the current
  388. front text file or a list of files, and to  view the results of a run; see “Calling hAWK
  389. through Minimal App” in the “Advanced topics” chapter for some tips on this. The
  390. discussion there is “advanced” only if you want to understand all the details—you
  391. can use the methods described there by rote (for example, if it says paste this bit
  392. of code into the top of a program and you’ll have support for taking input from a list
  393. of files, you can do it now and worry about how it works later).
  394.  
  395. ------------------
  396.     A typical hAWK run
  397. ------------------
  398. Have you installed hAWK yet? If not, now would be a good time (see above).
  399.  
  400. We’ll assume that you’re calling hAWK through an application that supports passing all
  401. or part of the front text window as input options, and showing stdout after a run, to
  402. make life simpler. If you don’t have such an application, you can use Minimal App in
  403. conjunction with whatever editor you are using to view this file, as described in the
  404. “Advanced topics” section “Calling hAWK through Minimal App”.
  405.  
  406. One of the programs supplied with hAWK is “$EnumSwitch”, which takes a list of
  407. enum constants and generates a “switch” statement based on them. It’s contained in the
  408. folder “hAWK programs”, which is inside the “Drag_on Modules” folder—you might
  409. like to take a look at it first....
  410.  
  411. OK, here we go: first, move this window on your screen so that you can see the next few
  412. lines while the hAWK setup dialog is in front (select hAWK now from the appropriate
  413. menu and Cancel to see where it appears). Now select the following line of text:
  414.     {first, second, third, fourth, twilightZone = -99}
  415. -is it highlighted? Good. Now, select hAWK from the menu; when the dialog
  416. appears, select “$Enumswitch” from the top popup menu called “Main program:”, and
  417. finally, click on the Run button or hit <Return> on the keyboard.
  418.  
  419. You should be back in the calling application now, with a switch statement coming up in a
  420. window called “$tempStdOut”. hAWK took the line that you highlighted above, stripped
  421. it down, built a switch statement out of the words, and wrote the results to the disk file
  422. “$tempStdOut”. The calling application is now showing you the resulting file, with
  423. contents selected and ready for pasting into your source code.
  424.  
  425. Most hAWK programs can be run this easily. Now, the full story.
  426.  
  427. ------------------
  428.     Running hAWK programs
  429. ------------------
  430.     The setup dialog
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449. When you select hAWK, the above “setup” dialog always appears first. A typical
  450. program run consists of: setting up the input to be ready for hAWK; selecting hAWK to
  451. see the setup dialog; selecting the program to run from the “Main program” popup
  452. menu; and hitting the Run button. If you have variables in the program that need
  453. to be set just before running the program, then you can set up to 10 variables by
  454. using the dialog that appears when you click the “Set variables” button. The input
  455. option, variable settings, and names of any associated libraries can all be saved with
  456. a hAWK program via the “Save settings” button, so that when you run a program again
  457. you‘ll need to adjust the setup only for things that have changed (typically only the
  458. values to be initially assigned to variables, if anything).
  459.  
  460.     Concurrent and immediate modes
  461. With most little languages, when you run a program that’s all you do—run the
  462. program. No continuing to work in your primary application, let alone switching to
  463. another application. In the rare case when you want hAWK to completely take over your
  464. Macintosh, locking you out of the calling application, hold down the <Shift> or <Option>
  465. key while selecting “hAWK” from the calling application’s menus. If the program uses
  466. the “prompt” or “progress” functions, it will be necessary to run in this
  467. “immediate” mode, since they just return null results in the “concurrent” mode.
  468.  
  469. In all other cases, just select “hAWK” from the calling application’s menus
  470. without holding down the <Shift> or <Option> key, and if the calling application
  471. supports it, you’ll be returned almost immediately to your application, able
  472. to carry on working there while the hAWK program runs at the
  473. same time. This “concurrent” mode of running programs does not greatly
  474. slow down the calling application or any other application that you switch to.
  475. The hAWK program itself will run more slowly than in immediate mode, often
  476. taking about 50% longer—but if you don’t need the results in a huge rush,
  477. stick to the concurrent mode and just forget about the hAWK program until
  478. it winds up with a beep.
  479.  
  480. While a hAWK program is running concurrently, you won’t by able to run any
  481. additional Drag_on Modules. This is because they all use the same standard output
  482. file ($tempStdOut), and a fight could develop over who gets to write to it.
  483.  
  484. While a hAWK program is running concurrently, you will not be able to save to
  485. any files that hAWK is using. Regular input files are accessed only one at a time,
  486. and the standard input/output/error files will normally be “busy” from
  487. beginning to end of the run. In addition, any files being read from or written to
  488. via redirection (see “Output” and “Input” chapters) will not be writeable.
  489. However, you will be able to open any file that hAWK is using to take a look
  490. at it. With a lengthy program, you can check in with hAWK now and then by
  491. opening (or reverting) $tempStdOut to get a snapshot of how things are
  492. progressing.
  493.  
  494. See the supplied program “$LogDaemon” for an example of a hAWK program which
  495. idles unobtrusively underneath your calling application, waiting to take special
  496. action when you copy a specific instruction to the application’s clipboard. A
  497. “daemon”, by the way, is an invisible, powerful spirit with your best interests
  498. at heart. It “possesses” your Macintosh, in a nice way. And the name is a bit more
  499. entertaining than the plain old “forks” and “threads” etc.
  500.  
  501. Concurrent execution is currently supported by: EnterAct.
  502.  
  503.     Selecting your program
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525. The “Main program:” popup at the top of the setup dialog lists all text files in the
  526. “hAWK programs” folder whose names begin with a dollar sign ($). This list is
  527. rebuilt each time you call hAWK. If a program is not listed in the popup, you can still
  528. run it by picking “Select unlisted program”, the first item in the “Main program”
  529. popup, and then using the standard Open dialog that appears to select the program—note
  530. it could be in another folder, or in the “hAWK programs” folder but not shown in the
  531. popup simply because its name doesn’t start with a “$”. You can avoid clutter in this
  532. popup by starting the names of only your most popular hAWK programs with a “$”, so
  533. that other less–frequently used programs won’t be shown in the popup—if they are in
  534. the hAWK programs folder, they will still be close at hand.
  535.  
  536.     Selecting input for a program
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555. This is one of hAWK’s nicest features, allowing hAWK to interact with the calling
  556. application to provide quick input file specification. Two additional ways of specifying
  557. input files, not listed in the “Take input from” popup, are described in the
  558. “Advanced topics” chapter, in “Other ways of specifying input files”.
  559.  
  560. Under the “Take input from” popup menu, the options “Front text selection” and
  561. “All of front text” refer to the text window that happens to be in front just before you
  562. call hAWK from the calling app’s menu. According to what you select here, all or just the
  563. selected part of the text in the front window will be written to a temporary file called
  564. “$tempStdIn”, and passed to your program as the input file to use. If your program
  565. is to be run using one of these options, bring the text window containing the text to be used
  566. as input to the front just before calling hAWK, and if you’ll be using the “Front text
  567. selection” option, you should select the text as well. For an example, see
  568. “A typical hAWK run” above, where this manual itself served as the front text.
  569.  
  570. The “MFS selected files” option in the “Take input from” popup refers to a list of files
  571. selected in the calling application for multi–file operations (typically this list is used
  572. mainly for multi–file searching in the calling application, and you construct it by
  573. placing check marks or bullets • beside file names—see the calling app’s manual for
  574. details). With this option selected, all files selected for multi–file operations will be
  575. passed to the hAWK program as input. This means you can set up a list of files in the
  576. calling app, and then have your hAWK program take its input from those files, from
  577. one file to hundreds. One limitation of this approach is that you can’t specify the exact
  578. sequence in which the files will be dealt with. With many programs, this is not a
  579. problem (multi–file search and replace, for example). To treat input files in a specific
  580. order see “Other ways of specifying input files” in the “Advanced topics” chapter.
  581.  
  582. The “Select input file…” option allows you to use a standard Open dialog to pick one
  583. specific file to use as input for a hAWK program. As with all other aspects of the
  584. setup dialog, if you click “Save settings” the name of the file you select will be saved
  585. with the program itself, and restored for the next run.
  586.  
  587. Aside from “Select input file…”, input options will not be shown if they are not
  588. currently available.
  589.  
  590. In rare cases, you may need no input at all for your program. To ensure that no
  591. input is passed, pick the “Select input file…” input option, cancel the Open dialog
  592. that appears, and then click the “Save settings” button. The input option for your
  593. program will thereafter read “Select input file…”, as though imploring you to
  594. pick one, but no input will be sent to your program. It’s harmless if input is sent
  595. to a program that doesn’t want any, the only penalty being time lost if a massive
  596. amount of input is accidentally ordered along for the ride.
  597.  
  598.     Setting variables
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625. The “Set variables” button allows you to preset the values of variables just before
  626. running a progam, without having to edit the program itself. As you can see from the
  627. picture, it’s a simple matter of typing the variable name, followed by an “equals”
  628. sign, followed by the value of the variable, either a number or a string.
  629.  
  630. Quotes should not be used to surround strings; just enter the string itself. Any
  631. spaces between the “=” and the value will count as part of the value, so normally
  632. you should enter the value with no spaces between the equals sign and the value.
  633. For example,
  634.     find =spot
  635. and
  636.     find = spot
  637. produce different results. Spaces are optional between the name of the variable
  638. and the equals sign.
  639.  
  640. The limit on the length of the variable assignment, including the name of the
  641. variable, is 100 characters. Up to 10 variables may be given values this way.
  642.  
  643. Special characters such as tabs and returns can be placed in a string by using the
  644. standard escape sequences familiar from C, eg
  645.         find =\tspot\n
  646. assigns to “find” the string consisting of a tab, followed by s-p-o-t, followed
  647. by a carriage return.
  648.  
  649. You can also assign the value of a (dynamic) regular expression using the “Set
  650. variables” dialog, for example
  651.     find =\.#[A-Za-z_]+            (never mind what it means for now)
  652. —note there is no need to enclose it in forward slashes, and many characters must
  653. be escaped with a backslash if you want them matched literally (the section 
  654. “Regular expressions” in the “Patterns” chapter explains the nuances).
  655.  
  656. Clicking the “Save settings” button will save your variable assignments for
  657. subseqent runs. Hence you’ll need to use the “Set variables” dialog only
  658. when the preset value of some variable changes.
  659.  
  660. If variable presets exist for a program then the “Set Variables” button will
  661. acquire a gray outline as a reminder that some variables may need changing
  662. before running the program. With some programs (such as $CompareFiles) you’ll
  663. almost never change the preset variables, but with others (such as $MFS_SuperLister)
  664. you’ll want to change one or more variables before almost every run.
  665.  
  666.     Library files
  667. Technically, this is an advanced topic, but it’s simple to use. If you develop
  668. some general–purpose functions, such as sorting routines, that you wish to
  669. use in several programs without duplicating the function definitions within
  670. each program, you can save the functions in a separate file and add that file
  671. to each main program as a library. The contents of the library file are
  672. simply appended to the contents of the main program before running it, so the
  673. library can in fact contain any valid hAWK statements. However, to preserve
  674. sanity, libraries should be restricted to just functions.
  675.  
  676. To add a library file to a main program:
  677. 1    Use the “Main program” popup to select the program
  678. 2    Use the “Select library…” item in the “Libraries:” popup to add the library
  679. by using the standard Open dialog that appears.
  680. 3    Clicking the “Save settings” button will preserve your selection of libraries
  681. for for subsequent runs.
  682.  
  683. To delete a library, select it using the “Libraries:” popup.
  684.  
  685. One sample library is included, in the file “SortLibrary”. It is not used in the
  686. sample programs, it’s just an example (PLEASE NOTE hAWK has its own
  687. built–in sort function, which is very fast). Little is lost if you follow the
  688. policy of not using libraries—programs are easier to read if all the code is in one place.
  689.  
  690.     Showing the results
  691. Output from hAWK programs is produced by “print” or “printf” statements,
  692. which send their output to the file “$tempStdOut” unless you explicitly
  693. redirect it. For example,
  694.         print "some text"
  695. will print the string "some text" to $tempStdOut.
  696.  
  697. The file $tempStdOut is created and managed for you, and most hAWK programs will
  698. send at least some output to this file. If you would like to see this file after the program
  699. is finished, put a check mark in the “Show stdout” checkbox in the setup dialog just
  700. before running the program. When the program is done, the calling application will
  701. then show you the $tempStdOut file in a window, if it is able to. If the calling
  702. application doesn’t support showing stdout, you’ll have to manually Open or Revert the
  703. $tempStdOut file using your editor (for more on this see “Calling hAWK through
  704. Minimal App” in the “Advanced topics” chapter).
  705.  
  706. Place a check mark in the “Select all of stdout” check box to have all of the output
  707. in the $tempStdOut window selected at the end of the program run. This is handy
  708. if you’ll be wanting to copy the entire output and paste it in elsewhere.
  709.  
  710.     Saving the setup for a program
  711. The “Save settings” button saves away your selection of options for a program, so that
  712. they will be restored for subsequent runs of the program. These options are saved with
  713. the program itself, in a special resource. The saved options are:
  714. 1    The names of any libraries associated with the program
  715. 2    Names and values of any preset variables
  716. 3    Your choice of input option, including the input file name if you have used
  717.     the “Select input file…” option to pick a specific file.
  718. 4     Your output options, in the checkboxes “Show stdout” and “Select all of stdout”.
  719.  
  720. During the first run of a program that you have written, you should set up the options
  721. you want and then click the “Save settings” button. Subsequent runs will then consist
  722. of just these steps:
  723. 1    Select “hAWK” from the calling application’s menu
  724. 2    Use the “Main program” popup to select the program
  725. 3    Use the “Set variables” button if needed to put in new values for variables
  726.     (many hAWK programs don’t need this)
  727. 4     Click the Run button.
  728.  
  729. Occasionally, you may want to run a program using a different input option, for example
  730. run it using “MFS selected files” rather than “All of front text”. This is simply a 
  731. matter of selecting the new input option from the “Take input from” popup just before
  732. running the program. If you want the input option to be permanently changed for the
  733. program, click the “Save settings” button after picking the new input option.
  734.  
  735.     Cancelling a run
  736. To cancel a hAWK program, hold down the <Command> key while typing a <period>.
  737. Program execution should cease within one second.
  738.  
  739. ------------------
  740.     Standard input and output
  741. ------------------
  742. Drag_on Modules such as hAWK and Read Resource use three disk files to communicate
  743. with you and with the calling application. These text files carry the burden of standard
  744. input/output for Drag_on Modules. If a Drag_on Module requires a large chunk of input
  745. that is not already in an appropriate disk file, the input will be written to the standard
  746. input file “$tempStdIn”, and all normal output from Drag_on Modules is, unless you
  747. specify otherwise, sent to the file “$tempStdOut”. If errors pop up while the Drag_on
  748. Module is running, error messages will be written to the file “$tempStdErr”. These
  749. files are all created and written to automatically as needed, and can be found in the same
  750. folder that contains your “Drag_on Modules” folder.
  751.  
  752. The file of main interest here is $tempStdOut, which typically holds the results of a
  753. Drag_on Module run. Drag_on Modules don’t show you this file, but can request that the
  754. calling application show it to you. This is always the case with Read Resource, and is
  755. optional with hAWK—it depends on whether you put a check in the “Show stdout”
  756. checkbox in the setup dialog. All of the supplied hAWK programs that write output to
  757. $tempStdOut have saved settings that include putting a check in this box.
  758.  
  759. Because the results of Drag_on Module runs are by default written to a fixed text
  760. file, you can easily pass the output from one run to the input of another run. For
  761. example, Read Resource creates a formatted text version of a resource and writes
  762. the results to $tempStdOut, which is then shown to you by the calling application.
  763. You can then call a hAWK program to further process this output, by leaving
  764. the $tempStdOut window in front and having the hAWK program take its input
  765. from the front window (pick the “All of front text” option from the “Take input
  766. from:” popup menu). And you can pass the output from one hAWK program to
  767. the input of another in the same way.
  768.  
  769. A Drag_on Module can only request that the calling application show you the
  770. $tempStdOut file, but whether or not it does so is up to the author of the calling
  771. application. If it doesn’t, you’ll have to Open or Revert $tempStdOut yourself
  772. in order to see the results.
  773.  
  774. The contents of $tempStdOut are indeed temporary, and will be overwritten by the
  775. next hAWK program, or indeed any other Drag_on Module, that you run. If you want
  776. a permanent copy of the output from a program, use “Save As” to save $tempStdOut
  777. under a new name, or copy the contents to a working window.
  778.  
  779. hAWK always takes input from a file, and if you are using one of the “front text”
  780. options for input then hAWK will write a copy of the front text to $tempStdIn before
  781. running your program. Output from hAWK programs, which is generated by “print”
  782. and “printf” statements, can be explicitly redirected to any file, but if no redirection
  783. is provided then by default the output from the program is sent to $tempStdOut. The
  784. file “$tempstdErr” will hold error messages if problems pop up while running a
  785. program.
  786.  
  787. Sometimes you’ll want to take input directly from the file $tempStdOut, without
  788. bothering to use the above method of opening the file and bringing its window to
  789. the front. It is perfectly OK to select $tempStdOut as the input file using the
  790. “Select input file...” option under the “Take input from:” popup. The contents
  791. of $tempStdOut just BEFORE the run will be used as the input, and input from
  792. this “old” version of $tempStdOut will not be affected by anything you write
  793. to $tempStdOut during the execution of your program. Actually, your old
  794. $tempStdOut will be renamed to $tempOutAsInput just before the run, and
  795. the file name your program receives will also be changed. This bit of suberfuge
  796. is necessary since it is not possible to randomly read and write the same file
  797. without things getting horribly confused.
  798.  
  799. ------------------------
  800.     About the supplied programs
  801. ------------------------
  802. For the most part, the programs you’ll find in the “hAWK programs” folder do useful
  803. things (from the point of view of a C programmer), with just a few of them being of the
  804. traditional “completely useless but illustrating some basic point” kind that are often
  805. foisted on innocent customers by authors who have run out of steam before writing the
  806. manual. There are nearly as many categories of supplied programs as there are
  807. supplied programs, so the following list with brief descriptions is in simple
  808. alphabetical order. The descriptions are brief here because each supplied program
  809. contains a detailed explanation of what it does and how to use it, at the top.
  810.  
  811. “$RunClip” provides a handy way to run small programs as you explore hAWK,
  812. without having to save them to disk first. You’ll find instructions below, and at
  813. the top of the $RunClip file.
  814.  
  815. Unless otherwise mentioned, a program sends its output to the file $tempStdOut, and
  816. you will be shown the contents of this file by the calling application at the end of the
  817. run (if it is able to do so). Most programs will accept input from any source, but then
  818. again most programs are especially useful with just one or two input sources.
  819. $EnumSwitch, for example, expects a comma–separated list of enum constants as
  820. input, normally provided by selecting the enum constants in a source code window and
  821. taking input for $EnumSwitch from the selected front text. Running this program on a
  822. batch of MFS selected files is possible, but wouldn’t produce very useful results. Once
  823. you understand roughly what a program does, you should be able to judge what sorts of
  824. input are appropriate for it.
  825.  
  826. The detailed instructions for running a program can be found at the top of the listing
  827. for the program itself, and you should read through those before running a program
  828. for the first time. For example, with $MFSLister you have to tell it what string
  829. to search for, and this is done by setting a variable with the
  830. “Set variables” button.
  831.  
  832. Programs which make essential use of the “progress” or “prompt” functions
  833. should be run in “immediate” mode (see “Running hAWK programs”,
  834. section “Concurrent and immediate modes”). To run a program in immediate
  835. mode, hold down the <Shift> or <Option> key while selecting “hAWK” from
  836. your application’s menus. Programs that should be run in immediate mode
  837. are marked with (IMM) just after the program name below.
  838.  
  839. $AddLineNumbers: will add line numbers to a file. Takes input from one specific
  840.     file, and overwrites the contents of the file. Doesn’t number blank lines.
  841. $Chain (IMM): allows you to run one or more small canned programs on your input,
  842.     the first program being executed using whatever input you specify, and
  843.     the following programs if any taking their input from stdout. You type
  844.     in the names of the programs to run in a dialog box, and they are executed
  845.     from left to right in the order you typed them. Effectively serves as a
  846.     “library” of small tasks. Illustrates using the hAWK() function to execute
  847.     a sequence of programs, repeatedly taking input from stdout, and the
  848.     “prompt” dialog box.
  849. $Comments: extracts lines that contain C comments. Or rather, at least all
  850.     lines that contain comments.
  851. $CompareFiles: prints differences between two versions of a file; for use with
  852.     the “MFS selected files” option. Has a couple of options, but should almost
  853.     always work fine with the defaults—see instructions if results seem suspicious.
  854.     Lengthy miscompares (over 100 lines) will cause it to bog down.
  855.     Demonstrates doing everything with functions rather than pattern–action blocks.
  856. $DefineSwitch: generates a “switch” statement, with cases created from a list
  857.     of #defined constants. Normally takes input from the selection in your front
  858.     text window, output is shown selected in $tempStdOut for copying to your
  859.     working window.
  860. $EchoFileNames: for use with the “MFS selected files” option, creates a list of
  861.     the file names that were selected.
  862. $EchoFullPathNames: like $EchoFileNames, but generates full path names in
  863.     the general form “Disk:folder:folder1:...:folderN:filename”. Full path names
  864.     are required when redirecting input and output of hAWK programs.
  865. $EnumSwitch: like $DefineSwitch, but generates the cases for the switch from
  866.     a comma–separated list of words, typically enum constants. Initializations
  867.     for any of the constants are ignored.
  868. $ExtractExternRefs: list all C declarations encountered that begin with “extern”.
  869.     Fast and simple, but will stumble if it encounters “extern” as the first word
  870.     in a comment. (Excercise: steal the comment–skipping code from $XRef
  871.     to fix this little problem).
  872. $FilesInOrderTest: discussed in the “Advanced topics” chapter way down below.
  873.     Demonstrates the technique of taking input from an arbitrary
  874.     list of files, the list itself being the sole input you pass to the program.
  875. $FindSetVolEtc: an example of a small program knocked off in a minute to
  876.     solve a specific search problem. Searches for a list of specific terms, prints
  877.     the file name and line number where found, together with the context of the find.
  878. $FrequencyWord: lists unique words in one or more documents, in declining order
  879.     of frequency. Demonstrates associative arrays and the sort command. A companion
  880.     to $WordFrequency.
  881. $List_Potential_C_Locals : feed this the body of a C function, and it will return a
  882.     list of candidates for declaration as local variables within the function. Contains
  883.     a near-complete lexical analyser for C, and produces best results if the calling
  884.     application supports the “lookup” function.
  885. $Lockout (IMM): (silly example, deleted)
  886.     
  887.     
  888.     
  889.     
  890.     
  891. $LogDaemon: the only supplied program that must be run in concurrent mode
  892.     only. It waits around until you copy the (almost) word "logit", flashes the
  893.     menu bar to acknowledge, and then will append the NEXT bit of text you
  894.     copy to a specific file, together with a date stamp. Then another flash to
  895.     signal that it’s done. This program runs until you type <Command><period>.
  896.     See instructions before using, since you’ll need to change the name of the log file.
  897. $LongestLines: will print out a list of the longest lines in one or more files. Use
  898.     “Set variables” to set how many lines to print, and how many spaces in a tab
  899.     before running. Properly converts tabs to spaces for calculating lengths,
  900.     illustrates several basic string functions.
  901. $LookupTest: a demonstration of the lookup() built–in function.
  902. $MFSLister: searches for a string or a regular expression (restricted to checking
  903.     one line at a time). Prints file name and line number where found, with optional
  904.     printing of the line containing the match.
  905. $MFS_SuperLister: searches for a regular expression or plain text involving
  906.     variable white space, can match it even if it spans a variable number of lines (try
  907.     that with Grep!). Lists file name and line where found. It’s up to you to
  908.     provide the text or regular expression. The innards are much like $MFS_SuperReplace.
  909. $MFS_SuperReplace: multi-file search and replace, searching for a regular
  910.     expression or a string of literal text that can span a variable number of lines.
  911.     Replacement text can replace or extend the pattern found. Alters the original files,
  912.     fully documents changes to stdout. Demonstrates using the hAWK() function
  913.     to selectively alter and execute a program, handling a variable number of
  914.     input lines at once in a “rolling buffer”.
  915. $Print_MENU_Resource: given the result of Read Resource on a MENU resource,
  916.     this program prints a nicely–formatted version of the menu. A sample for doing
  917.     your own custom resource or data formatting and content verification, including
  918.     all of the necessary basic functions for doing so.
  919. $Print_MPSR_1007: given the result of Read Resource on a “MPSR 1007” resource
  920.     (ie marks for a text file), prints out a nice version (see also $Print_MENU_Resource).
  921. $printNF: trivial, prints the number of fields in each input line.
  922. $ProgressTest, $PromptTest (IMM): demonstrate the prompt() and progress() functions.
  923.     (for a nice little prompt()
  924.     example, see $YoungMath).
  925. $RoughIndexer: if you dream of automatically generating an index, you can
  926.     start here.
  927. $RunClip: for short, disposeable programs to be run concurrently (note that $Type&Run
  928.     only runs in immediate mode). The calling application must support passing its
  929.     clipboard to hAWK (eg EnterAct). Create your program in the calling app, Copy it,
  930.     bring input to hAWK's attention (eg front text or a multi-file selection), then call
  931.     up hAWK and select and run $RunClip. Your copied program will be saved to the file
  932.     “$hAWKTempProgram”, and then executed using the built-in hAWK() function.
  933. $SortTest: a test of the built–in sort() function, doing dictionary order. For
  934.     a real use, see $WordFrequency.
  935. $SortTest_Nums: a sort() test on numbers. Uses rand() to generate the numbers.
  936. $StubFunctions: given a list of C function prototypes, generates empty function
  937.     shells for the function definitions.
  938. $TabsToSpaces: converts tabs to spaces in one or more documents, replacing each tab
  939.     by the appropriate number of spaces (anywhere from 1 to “spaces_in_tabs”),
  940.     consistent with the tab interpretation of THINK C et al. You set the
  941.     number of spaces in a tab with “Set variables”, and also whether to overwrite
  942.     the original file or make a copy with a new name. Demonstrates some
  943.     basic file–handling methods
  944. $Time: just prints out the time, using the TIME built–in variable, and the
  945.     time() function for comparison.
  946. $TwoColumnsRight: given a list of numbers in two columns, right–justifies
  947.     the numbers in the columns. Demonstrates dynamically building
  948.     a printf() format string with variables and string concatenation.
  949. $Type&Run (IMM): for short, disposeable programs, use the dialog box presented by this
  950.     program to type in and run your one or two-liner. Since <Return> means “OK”
  951.     in the dialog, use <Command><Return> to advance to a new line. Illustrates using
  952.     the hAWK() function to save and execute a program.
  953. $Uppercase: changes the first letter in each input field to upper case if
  954.     it is a lower case letter. Uses match(), sub(), substr().
  955. $Whazzat: translates C declarations into English. Works best if the calling
  956.     application supports the “lookup” function so that special terms in your
  957.     declaration (typedefs, struct tags etc) can be diagnosed.
  958.     Illustrates using functions instead of pattern–action blocks, retrieving tokens
  959.     with string functions while parsing, reformatting long lines for output.
  960. $WordFrequency: a “classic” use for AWK - print sorted list of unique words
  961.     in the input, together with the number of times each word is used.
  962. $XRef: generates file and line number listing for your choice of terms in C source
  963.     code. Illustrates the hAWK() function, sorting. The calling application must
  964.     support the “lookup” function (see “Built–in string and file functions” in the
  965.     “Actions” chapter).
  966. $XRef_Full: like $XRef, but doesn’t skip comments and strings.
  967. $YoungMath (IMM): demonstrates the prompt() function while urging you to add
  968.     numbers.
  969.  
  970. ---------------------
  971.     hAWK program structure
  972. ---------------------
  973.     From start to finish
  974. A typical hAWK program run progresses as follows:
  975. 1    From the hAWk setup dialog, specify the main program to be run, add any library files
  976. that go with it (optional), specify initial values for variables (optional), and build
  977. a list of input text files for the program to work on (optional, but almost always
  978. included).
  979. 2    Collect the main program and libraries together into one big program. Reduce it
  980. to a form more suitable for interpretation. Assign initial values to variables if you
  981. have provided any. The list of input files is made available to the program,in the
  982. array ARGV[] of file names.
  983. 3    Execute the program: by default, hAWK automatically reads the text from the input
  984. files into memory, one “record” at a time (the default is that a line is a record). If
  985. a record matches one of your specified patterns, then action is taken. Statements may
  986. optionally be executed before and after the input is dealt with. Schematically, a
  987. generic hAWK program looks like
  988.             #An abstract hAWK program:
  989.             BEGIN {beginning statements}
  990.             pattern1 {action statements for pattern1}
  991.             ...
  992.             patternN {action statements for patternN}
  993.             END {ending statments}
  994.             (--supporting function definitions--)
  995. and the corresponding program execution proceeds as follows:
  996.         •    execute any supplied BEGIN statements
  997.         •    read the input files into memory, one record at a time; for each record
  998.         check all patterns; if the pattern is TRUE for the current input record,
  999.         execute the associated action statements; in C this would look like:
  1000.                     while (get_another_input_record())
  1001.                         {
  1002.                         for (pattern1 to patternN)
  1003.                             {
  1004.                             if (pattern is TRUE)
  1005.                                 {
  1006.                                 action statements for the pattern
  1007.                                 }
  1008.                             }
  1009.                         }
  1010.         •    execute any END statements
  1011. 4    Unless otherwise specified by redirection, all output via “print” or “printf”
  1012. statements goes to the default standard output file, called “$tempStdOut”.
  1013. 5    Comments in the source code, which begin with a “#” and continue to the end
  1014. of the line, are ignored.
  1015.  
  1016. BEGIN, END, and pattern–action blocks may occur in any order in the source for
  1017. the program. Programs may also contain function definitions, which are
  1018. introduced by the “function” keyword, and take the general form:
  1019.         "function" funcName(parameter1, parameter2,...local variables)
  1020.             {
  1021.             statements making up the function body
  1022.             }
  1023. If a function is generally useful, it may be placed in a library file to save duplication.
  1024. You’ll find little emphasis on libraries, since it costs very little to duplicate a function
  1025. right in the main program, and this makes the programs easier to read.
  1026. Library files should be reserved solely for function definitions to avoid confusion.
  1027.  
  1028. hAWK automatically reads in your input files one “record” at a time, also breaking each
  1029. record into “fields”. The current record is in the built-in variable $0, and the fields
  1030. are in $1, $2, …$NF (where NF is another built-in variable giving the number
  1031. of fields in the current record). By default a record is the same as a line and fields are
  1032. separated by blanks or tabs, so you can think of the default as reading your input one
  1033. line at a time into $0 and making the inidividual words available in $1, $2 etc (but note
  1034. that all punctuation except blanks, tabs, and returns will still be present in the fields).
  1035. For example, if the current line in an input file reads
  1036.     "for (i = 0; i<7; ++i)"
  1037. then that will be the content of $0, and the fields will be
  1038.     $1 = "for", $2 = "(i", $3 = "=", $4 = "0;", $5 = "i<7;", $6 = "++i", with
  1039. NF, the current number of fields, set to 6.
  1040.  
  1041. Here’s a real program to give you a taste ("$EnumSwitch", in the “hAWK
  1042. programs” folder):
  1043.         #$EnumSwitch
  1044.         #Select a bunch of enums, and run Hawk on the front selection
  1045.         # -optionally select the entire enum body from '{' to '}' with Balance
  1046.         #Leave "Show std out" and "Select all of stdout" checked
  1047.         
  1048.             {    gsub(/=[^,]*/, " ")#remove initializations for the enum constants
  1049.                 gsub(/=(.)*$/, " ")#ditto
  1050.                 gsub(/[,{};]/, " ")#remove remaining punctuation, leaving just the enums
  1051.                 for ( k = 1; k <= NF; k++)#build an array containing the enum names
  1052.                     case[++i] = $k
  1053.             }
  1054.         
  1055.         END    {    print "switch (??)"
  1056.                 print "\t{"
  1057.                 for (k = 1; k <= i; ++k)
  1058.                     {
  1059.                     print "case " case[k] ":"
  1060.                     print "\t"
  1061.                     print "break;"
  1062.                     }
  1063.                 print "default:"
  1064.                 print "\t"
  1065.                 print "break;"
  1066.                 print "\t}"
  1067.             }#end program
  1068. Given a list of names from an enum definition, such as
  1069.         "{left, right, up, down, twilightZone = 999}" this program generates
  1070.         switch (??)
  1071.             {
  1072.         case left:
  1073.         
  1074.         break;
  1075.         ...etc…
  1076.         case twilightZone:
  1077.         
  1078.         break;
  1079.         default:
  1080.         
  1081.         break;
  1082.             }
  1083. To run this program: first select a list of comma-separated names (typically use the
  1084. contents of an enum definition); select "hAWK" from the calling application’s menu;
  1085. select "$EnumSwitch" from the "Main program" popup; (note the "Take input from:"
  1086. popup will then read "Front text selection"); and click the Run button. The generated
  1087. "switch" statement will appear in a window called "$tempStdOut", ready to be copied
  1088. and pasted into your working window.
  1089.  
  1090.     Grouping and breaking lines
  1091. The rules for organizing and grouping your program lines differ a bit from the rules
  1092. for C; a <Return> (also called newline) can stand for a semicolon after most hAWK
  1093. statements, the price of this being that lines cannot be arbitrarily broken as in C,
  1094. to avoid confusion between ending a statement and merely continuing it to the next
  1095. line. The rules below are listed in rough order of their impact on whatever C
  1096. formatting habits you have.
  1097.  
  1098. • When in doubt, use a backslash '\' immediately followed by a <Return> to continue a
  1099. long line, as with preprocessor macro’s and strings in C. For example:
  1100.         x = y + (z - 1) + SomeFunction(param1, param2\
  1101.                                         , param3, param4) + w;
  1102. •    Long conditional tests can be broken to the next line immediately after any logical
  1103. operator (&&, ||, !). Eg:
  1104.     if (    lineNumber >= maxLines &&
  1105.             $0 != "")
  1106. •    A long line may be broken after a comma, eg
  1107.     x = y + (z - 1) + SomeFunction(param1, param2,
  1108.                                     param3, param4) + w;
  1109. •    The '{' that begins an action should be placed on the same line as the end of the
  1110. pattern for it, eg
  1111.     FNR == 1 || FNR == 2 ||
  1112.     FNR == 3        {        #Note '{' is on same line as end of pattern
  1113.                         print
  1114.                         }
  1115. •    A comment in hAWK begins with a '#' and continues to the end of the line. A comment
  1116. can be placed at the end of any line except a line that is continued with a backslash and
  1117. <Return>.
  1118. •    Group multiple statements together with '{' and '}', as in C, eg
  1119.     if ($0 ~ /TEST/)
  1120.         {
  1121.         print "TEST on line", FNR
  1122.         ++numTests
  1123.         }
  1124. •    When in doubt, terminate a single statement with a semicolon. Multiple statements
  1125. may be placed on one line if separated by semicolons, eg
  1126.     if (a >= b) print "a is bigger"; else print "b is bigger";
  1127. or
  1128.     do ++x; while (x < maxForX);
  1129. •    In if-else and do-while constructs, the “else” and “while” keywords should either
  1130. be placed on a new line or preceded by a semicolon or '}'. In other words, clearly
  1131. signal the end of the “if” or “do” part, so that the “else” or “while” doesn’t pop
  1132. up by surprise:
  1133. these are OK;
  1134.     if (a > b) ++b; else ++a
  1135.     
  1136.     if (a > b) ++b
  1137.     else ++a
  1138.     
  1139.     do {--x; print x} while (x > 0)
  1140.  
  1141. these are not;
  1142.     if (a > b) ++b else ++a
  1143.     
  1144.     do ++x while (x < maxForX);
  1145.  
  1146. ----------------------
  1147.     The Command line and ARGV[]
  1148. ----------------------
  1149. To run a hAWK program, you must tell hAWK which program to run, and what files
  1150. to use for input data, with other optional details. Classically, these file names etc
  1151. are passed to AWK in an array of pointers called argv; hAWK works the same way,
  1152. but these names are generated for you when you set up a hAWK run using the
  1153. setup dialog, saving you the work of typing them all in each time.
  1154.  
  1155. All you really need to know about the command line is that, at the time a program
  1156. is run, the names of the input files it is being asked to deal with are contained in
  1157. the array named ARGV, and the number of input files equals ARGC-1 (where
  1158. ARGV is a built-in array name, and ARGC is a built–in variable name). Input file
  1159. names are full path names, so typical contents are
  1160.         ARGV[1] = "Disk:folder:...:folder:First_Input_file"
  1161.         ...
  1162.         ARGV[ARGC-1] = "Disk:folder:...:folder:Last_Input_file".
  1163. Running the sample program “$EchoFullPathNames” on some input files will provide
  1164. you with a specifc example—why not give it a try? Use your calling application to
  1165. select some files for multi–file operations (“searching”), then run
  1166. $EchoFullPathNames and see what results. This is the complete program:
  1167.         BEGIN {
  1168.             for (i = 1; i < ARGC; ++i)#note ARGV[0] is just "hAWK"
  1169.                 print ARGV[i]
  1170.             }
  1171.  
  1172. Details follow on the command line generated by hAWK’s setup dialog, in case you
  1173. are interested in modifying hAWK. You may also find this background helpful if you
  1174. use the hAWK() function, which executes another program from within a program
  1175. and requires an explicit command line as its argument (see ch. Q, “The hAWK function”).
  1176.  
  1177. The command line passed to hAWK from the setup dialog takes the general form
  1178.         hAWK -fProgramName {-fLibraryName} {-vVariable=value} --
  1179.             {InputFileName}
  1180. where the {} brackets indicate that an item may be repeated or omitted. For example, if
  1181. running a program "$BigSort" with supporting library "Sort_Routines", with the files
  1182. to be sorted being "Text1" and "Text2" then the command line passed to hAWK by the
  1183. setup dialog will be something like
  1184.     hAWK -f$BigSort -fSort_Routines -- HardDrive:Code Folder:Sub Folder:Text1
  1185.             HardDrive:Code Folder:Sub Folder:Text2
  1186. The "-f", "-v", and "--" are little markers that hAWK uses to tell what's what.
  1187. "-f" means a program file, "-v" means a variable assignment, and "--" means
  1188. that ony input files (if anything) follow this marker.
  1189.  
  1190. By the time the command line becomes available to you within your hAWK program,
  1191. the array "argv" is a hAWK array of strings called "ARGV" that contains only "hAWK"
  1192. in ARGV[0] followed by the names of the input files in ARGV[1], ARGV[2] etc,
  1193. and ARGC is set to the number elements in the ARGV array, namely the number of
  1194. input files plus one.  The last input file name is ARGV[ARGC-1].
  1195.  
  1196. Normally, the input file names are the only things on the command line of interest
  1197. that you don't already have access to. You'll have acess to the variables anyway,
  1198. and one can't help thinking that it would be an odd program indeed that needed to know
  1199. its own "ProgName".
  1200.  
  1201. Here's a hAWK program that prints a complete list of the input file names passed
  1202.  to it ($EchoArgs again):
  1203.  BEGIN        {
  1204.                 for (i = 1; i < ARGC; ++i)#note ARGV[0] is just "hAWK"
  1205.                     print ARGV[i]
  1206.                 }
  1207. If you included this block in $BigSort above, then the output would be something like
  1208.     HardDrive:Code Folder:Sub Folder:Text1
  1209.     HardDrive:Code Folder:Sub Folder2:Text1
  1210. —as you can see, you're getting the full path names of the file, not just the file names.
  1211. Here's a version that prints just the file names proper:
  1212.  BEGIN        {
  1213.                 for (i = 1; i < ARGC; ++i)
  1214.                     {
  1215.                     n = split(ARGV[i], names, ":")
  1216.                     print names[n]
  1217.                     }
  1218.                 }
  1219. for which the output would for example be
  1220.     Text1
  1221.     Text2
  1222. The important thing to note here is that hAWK deals with full path names for files,
  1223. especially relevant if you are redirecting input or output (more on this later).
  1224.  
  1225. When you assign values to variables using the "Set variables" button in the setup
  1226. dialog, the result is the same as if you assigned the value in the BEGIN block of
  1227. your program. However, you should NOT use quotes if you are assigning a text
  1228. string to a variable using "Set variables"—for example, the variable assignment
  1229.     find=text to find
  1230. within the "Set variables" dialog is equivalent to the statement
  1231.     BEGIN {find = "text to find"}
  1232. within your actual program. This is meant to be a convenience, but is perhaps a
  1233. nuisance, in that any spaces between the '=' and the value are significant:
  1234.     find =text
  1235. is not the same as
  1236.     find = text
  1237. —that space between the '=' and the 't' of "text" will be included in the string for "find".
  1238.  
  1239. The "Set variables" button can be used to set the value of any hAWK variable,
  1240. whether your own or a predefined (built-in) variable, and it is easier to change
  1241. a variable this way than to edit the program itself. Up to 10 variables can be set
  1242. with "Set variables", and your variable settings will be saved for the next run
  1243. if you click the "Save settings" button in the setup dialog. For an illustration and
  1244. more details, see the “Running hAWK programs” chapter.
  1245.  
  1246. ----------------
  1247.     Variables and constants
  1248. ----------------
  1249.     Variable names and types
  1250. hAWK has many built–in variables, and you can use your own. A variable of your
  1251. own devising springs into existence when you first use it, with no need to declare
  1252. it (excepting perhaps local variables for functions, which need to be not so much
  1253. declared as “mentioned”—see “Local variables in functions” below).
  1254.  
  1255. Variable names in hAWK take the same form as C names: a letter or underscore
  1256. followed by any number of letters, underscores, and numbers.
  1257.  
  1258. hAWK has both scalar variables and one–dimensional arrays. The value of a variable or
  1259. array element may be a (floating–point) number OR a string, and the specific type at
  1260. any time depends on how you use the variable. While numeric values in hAWK are
  1261. nominally floating–point, if you consistently use a variable as an integer you will
  1262. get predictable results. For example,
  1263.             for (i = 0; i <= 1; ++i)
  1264.                 print i
  1265. will print two values, 0 and 1, guaranteed.
  1266.  
  1267. Uninitialized variables have the numeric value 0 and the string value "" (the null, or
  1268. empty, string). Note this differs from a variable that has been explicitly initialized
  1269. to zero, for in this case while the numeric value will be zero the string value
  1270. will be "0".
  1271.  
  1272.     Constants
  1273. Constants can be integers, floating–point numbers, or strings. For example,
  1274.         x = "A string of text";
  1275.         y = 7;
  1276.         z = .31415926E1;
  1277.         pat = "[_A-Za-z][_A-Za-z0-9]*"; (a string to be interpreted as a regular
  1278.                 expression - it matches a hAWK variable name).
  1279.  
  1280.     Record and field variables
  1281. After the BEGIN block(s) of a program have been executed, a hAWK program proceeds
  1282. to automatically retrieve records from your input files one at a time to the built–in
  1283. variable $0, and individual fields in the current record can be accessed with the
  1284. built–in variables $1, the first field, $2 etc up to $NF, the last field, where NF is
  1285. a built–in that records the current number of fields. Records are separated according
  1286. to the string contained in the built–in record–separator variable, RS. By default
  1287. this contains just a return, ie RS = "\n", so a record is the same as a line. You can
  1288. change the value of RS, and setting RS to ""(the null string) will cause empty lines
  1289. to be treated as the record separator. Note that the record separator itself is
  1290. trimmed from the record.
  1291.  
  1292. Similarly, fields are separated in accordance with the value of the field–separator
  1293. variable, FS. By default the field separator is a regular expression standing for
  1294. “one or more blanks or tabs”, and as a nicety if you use the default value of FS then
  1295. any leading blanks or tabs will be trimmed away from the first field, $1.
  1296.  
  1297. References to non-existent fields (fields after $NF ), produce the null-string.
  1298. However, assigning to a non-existent field (e.g., $(NF+2) = 5 ) will increase the
  1299. value of NF , create any intervening fields with the null string as their value, and
  1300. cause the value of $0 to be recomputed, with the fields being separated by the value of
  1301. OFS, the output field separator. A negative field number is an error.
  1302.  
  1303. Many functions in hAWK allow you to optionally specify a string for them to work on,
  1304. and if you don’t specify a string then it uses $0, the current input record, by default.
  1305. For example, 
  1306.         print "some text"
  1307. will do just that—print the string "some text" to the standard output, whereas
  1308.             print
  1309. all by itself, will print the contents of $0 to stdout, and thus it has the same effect as
  1310.             print $0
  1311. Note that “print” tags on the contents of ORS, by default a return, to its output, so in the
  1312. default case the return that was trimmed away when retrieving the current input
  1313. record is added back. Thus, the hAWK program that consists of the one line
  1314.         {print}
  1315. will echo all of its input to stdout (the file $tempStdOut) without change, though a flurry
  1316. of activity involving returns takes place behind the scenes.
  1317.  
  1318. This little program prints the individual fields of each input record to individual lines:
  1319.     {for (i = 1; i <= NF; ++i)
  1320.         print $i
  1321.     }
  1322. —note that the field specifier can be a variable as in “$i”, and doesn’t have to be
  1323. a constant. 
  1324.  
  1325.     Built–in variables
  1326. hAWK's built-in variables are:
  1327. ARGC            the number of input files plus one
  1328. ARGV            array of command line arguments. The array is indexed from 0 to ARGC - 1,
  1329.                     the input file names being ARGV[1] through ARGV[ARGC-1].
  1330.                     Dynamically changing the contents of ARGV can control the files used for data.
  1331. FILENAME    the name of the current input file. If no files are specified on the command line,
  1332.                     the value of FILENAME is "-". A hAWK program may do all of its work in a BEGIN
  1333.                     block, with no need for input (generating a list of random numbers for example).
  1334. FNR                the input record number in the current input file. Reset to 1 when starting a new
  1335.                     input file. Hence the pattern “FNR == 1” detects the start of each file.
  1336. FS                the input field separator, a blank by default. If the default FS is used then
  1337.                     leading blanks and tabs are trimmed from $1.
  1338. IGNORECASE    controls the case-sensitivity of all regular expression operations.
  1339.                     If IGNORECASE has a non-zero value, then pattern matching in
  1340.                     rules, field splitting with FS , regular expression matching with
  1341.                     ~ and !~ , and the gsub() , index() , match() , split() ,
  1342.                     and sub() pre-defined functions will all ignore case when doing
  1343.                     regular expression operations. Thus, if IGNORECASE is not equal to
  1344.                     zero, /aB/ matches all of the strings "ab", "aB",
  1345.                     "Ab", and "AB". The initial value of IGNORECASE is zero, 
  1346.                     so all regular expression operations are normally case-sensitive.
  1347. NF                the number of fields in the current input record.
  1348. NR                the total number of input records in all input files seen so far.
  1349. OFMT            the output format for numbers, %.6g by default.
  1350. OFS                the output field separator, a blank by default.
  1351. ORS                the output record separator, by default a newline.
  1352. RS                the input record separator, by default a newline. RS is exceptional
  1353.                     in that only the first character of its string value is used for
  1354.                     separating records. If RS is set to the null string, then records are
  1355.                     separated by blank lines. When RS is set to the null string, then
  1356.                     the newline character always acts as a field separator, in addition
  1357.                     to whatever value FS may have.
  1358. RSTART        the index of the first character matched by match(); 0 if no match.
  1359. RLENGTH        the length of the string matched by match(); -1 if no match.
  1360. SUBSEP        the character used to separate multiple subscripts in array
  1361.                     elements, by default "\034", some kinda up arrow very rare in text.
  1362. (and three added for the Macintosh version)
  1363. RUNERR        short for "run error", a file name that you can use to print your own error
  1364.                     messages to, as in         print "Error during run" > RUNERR. Default name
  1365.                     is $tempRunErr, and you'll find the file in the same folder as $tempStdOut.
  1366. STDPATH        path name that can be prefixed to any file name you wish to be written to the
  1367.                     same folder as stdout ($tempStdOut). Typically looks like
  1368.                     "Disk:folder1...:THINK C folder:" and typical use looks like
  1369.                             outname = "MyOutFile"
  1370.                             fullOutName = STDPATH outname;
  1371.                             print "something" > fullOutName;
  1372. TIME            at start of run, eg "Sunday, October 13, 1991 07:58 AM"
  1373.  
  1374.     Local variables in functions
  1375. Function definitions in hAWK resemble those of C a bit, but local variables require
  1376. an odd syntax. They must be listed in the parameters of the function, after the real
  1377. parameters, in order to be treated as local. All other variables in hAWK have global
  1378. scope. For example, in
  1379.         function SumArray(arr,     index, sum)
  1380.             {
  1381.             for (index in arr)
  1382.                 sum += arr[index];
  1383.             return sum
  1384.             }
  1385. the only real parameter is the array name “arr”. This function sums up the contents of
  1386. the array and returns the sum, used as in “sum = SumArray(x);” where x is an
  1387. array containing numbers. The variables “index” and “sum” look like orphans there
  1388. in the parameters, but this is just the hAWK way of declaring local variables. Both
  1389. index and sum cannot be affected by any statements outside the SumArray function (that
  1390. is, they are local in scope), and as a bonus hAWK initializes even local variables to 0
  1391. each time the function is called. Functions are described in more detail a little later in
  1392. the chapter “User-defined functions”.
  1393.  
  1394.     Setting variables on the command line
  1395. When variables are set using the “Set variables” option in the setup dialog, no quotes
  1396. should be used around strings, and no space should be put between the equals sign and
  1397. the string or number unless you want it to be included in the value. For example, the
  1398. equivalent of
  1399.         BEGIN {find = "some text to find"; first = 7;}
  1400. in the “Set variables” dialog would be
  1401.         find =some text to find
  1402.         first =7
  1403. (the space before the equals sign is optional).
  1404.  
  1405.     Conversion between numbers and strings
  1406. Conversion of a variable’s value between number and string is automatic in hAWK when
  1407. circumstances call for it, and can be forced by you as well. When an operator is strictly
  1408. numeric, the value of its operands will be forced to numbers if necessary, and similarly
  1409. if an operator expects to deal strictly with strings then values will be forced to strings.
  1410.  
  1411. For example, in 
  1412.         a = "102";
  1413.         b = a + 1;
  1414. “a” starts out as a string, but the “+” operator deals strictly with numbers, so “a”
  1415. is converted to the number 102.0 on the second line.
  1416.  
  1417. And in
  1418.     a = 27;
  1419.     b = "trombones";
  1420.     c = a b; #there is a space between a and b
  1421. we see the invisible “concatenation” operator at work. Two variables or constants separated
  1422. by just a space are treated as strings by hAWK and concatenated together. So “a” is converted
  1423. to a string on the third line, and “c” ends up holding the string "27trombones".
  1424.  
  1425. Some operators (all of the comparison operators == <= >= etc for example) can accept
  1426. either strings or numbers. When this is the case, the rule is that the operation proceeds
  1427. numerically if both operands are currently valid numbers, but proceeds as a string operation
  1428. otherwise. 
  1429.  
  1430. You can force a variable to be treated as a string by concatenating the null string to it. For
  1431. example, no matter what the values of a and b are, the comparison
  1432.         a "" == b
  1433. will proceed as a string comparison.
  1434.  
  1435. And you can force a variable to be treated as a number by adding 0 to it, as in
  1436.         a + 0 == b + 0
  1437. but note in this case that both operands should be forced to numeric type.
  1438.  
  1439.      Arrays
  1440. Arrays are subscripted with an expression between square brackets, arr"["expr"]".
  1441. Array values can be numbers or strings, but the index is always interpreted as
  1442. a string. For example, when you write
  1443.     arr[1]
  1444. the 1 is converted to the string "1" for use as the array index, so arr[1] is
  1445. the same as arr["1"]. This sort of array is called “associative” since it can
  1446. associate one string of text with any other, eg
  1447.         arr["John Henry"] = "was a log-drivin man"
  1448.  
  1449. If the index expression is an expression list ( expr1,  expr2, expr3,... ) then the array
  1450. subscript is a string consisting of the concatenation of the (string) value of each
  1451. expression, separated by the value of the SUBSEP variable, which is by default
  1452. “\034” (decimal 28, an up arrow). This facility is used to simulate
  1453. multiply–dimensioned arrays. For example:
  1454.     i = "A" ; j = "B" ;k = "C"
  1455.     x[i, j, k] = "hello, world"
  1456. assigns the string "hello, world" to the element of the array x
  1457. which is indexed by the string "A\034B\034C".
  1458.  
  1459. The special operator "in" may be used in an "if" statement to see if an array has
  1460. an index consisting of a particular value:
  1461.     if (val in array)
  1462.         print array[val]
  1463. If the array has multiple subscripts i j k, use
  1464. if ((i, j,k) in array) instead . The alternate
  1465.     if (array[val] != "")
  1466. actually creates the array array[val] element if it does not exist, so using “in”
  1467. is usually better.
  1468.  
  1469. The "in" construct may also be used in a for loop to iterate over all the elements of an
  1470. array:
  1471.     for (i in arr)
  1472.         delete arr[i] # or         print arr[i]   , or             print i, arr[i]
  1473. An element may be deleted from an array using the delete statement. New elements should
  1474. not be added to an array while looping over it with the "in" for-loop, since hAWK isn’t
  1475. quite smart enough to handle that very well.
  1476.  
  1477. Behind the scenes, indexes for an array are stored in a hash table, Retrieval of an array
  1478. element takes constant time up to a moderate array size (~1000), but as array size
  1479. increases retrieval time will increase as a linear function of the size.
  1480.  
  1481. Some array examples:
  1482.     for (i = 1; i <= 100; ++i)
  1483.         x[i] = i;
  1484. This does what you would expect, creating x[1] =1, ...x[100] = 100. Note, however, that
  1485. while i is treated as an integer in the for loop, it is converted to the string representation
  1486. for that number when used as the index for x.
  1487.  
  1488.     for (i = 1; i <= NF; ++i)
  1489.         wordCounter[$i] += 1;
  1490. Here we see the real power of hAWK’s associative arrays. $i is a string containing a field
  1491. on the current input line, and this string is used as an index into the wordCounter array.
  1492. If there is no element in the array yet for the index, a new element is created (and
  1493. initialized to 0/the null string, as for regular variables). The array element itself holds
  1494. just a count of how many times the string has been seen. Obviously, you can’t access these
  1495. array elements by incrementing a numeric index—here’s where “in” comes in:
  1496.     for (word in wordCounter)
  1497.         print word, "was seen", wordCounter[word], "times."
  1498. prints out the words used to index wordCounter, together with the word counts, a sample
  1499. line being
  1500.     parsimonious was seen 1 times.
  1501. The one drawback of this simple example is that the words will be printed in a rather
  1502. arbitrary order (internally, the entries in a hash table are being accessed). However,
  1503. even this shortcoming can be overcome. The sample program “$WordFrequency”
  1504. shows how to sort an array such as wordCounter into dictionary order on the index.
  1505.  
  1506.     while (getline x > 0)
  1507.         lines[++n] = x;
  1508. The “getline x” will retrieve records from your current input file to the variable x,
  1509. from the current position to the end of the file. Each record is saved away as an element
  1510. in the array “lines”. Here the index is a number (technically the string for the
  1511. number) and the element is a string —the reverse of the last example.
  1512.  
  1513.     times[3,7] = 21;
  1514. The actual index is "3" "\034" "7" concatenated together. A multi-dimensional
  1515. array can be run through in the same way as in C:
  1516.     for (i = 1; i <= iMax; ++i)
  1517.         {
  1518.         for (j = 1; j <= jMax; ++j)
  1519.             {
  1520.             print times[i,j] #or whatever
  1521.             }
  1522.         } # note "for (k in times) print times[k]" could also be used.
  1523.  
  1524. -------
  1525.     Patterns
  1526. -------
  1527.     Patterns and actions
  1528. At the top level, a hAWK programs consists of patterns and actions, of the general form
  1529.     pattern    {    action    }
  1530. When a pattern evaluates to true (non–zero), the corresponding action is taken.
  1531. Patterns resemble the conditions found in a C if-statement, but several kinds of
  1532. patterns, notably BEGIN, END and patterns using the matching operator '~', are not
  1533. found in C. As described earlier, hAWK will automatically read in your input one
  1534. record at a time to the variable $0, and each pattern is evaluated in turn; if the pattern
  1535. is true for the current input, then the action statements are executed.
  1536.  
  1537. A missing pattern evaluates to true, so action statements with no preceding pattern
  1538. are executed for every input record. A missing action is equivalent to
  1539.     { print }
  1540. which prints the input record to stdout. It’s equivalent to {print $0}, by the way.
  1541.  
  1542. Here’s a sample pattern-action block that is often useful:
  1543.     FNR == 1 {    z = split(FILENAME, names, ":") }
  1544. FNR stands for "file number of records", reset to 1 at the beginning of each input file.
  1545. FILENAME is a variable holding the full path name of the current input file. The split on
  1546. ':' splits FILENAME into an array, treating the ':' as the element separator. Often, one
  1547. wants just the file name proper without the disk and folders, and this is given by
  1548. names[z]. For example, if FILENAME = "Disk:folder:thefile" then the split produces
  1549. names[1] = "Disk", names[2] = "folder", and names[3] = "thefile", with "z" being
  1550. set to 3. The statement "print names[z], FNR" will print the current input file name
  1551. and current line number to stdout.
  1552.  
  1553. The “Summary of patterns” section at the end of this chapter contains a small program
  1554. that will let you try out patterns as they occur to you. Or you could use $RunClip.
  1555.  
  1556.     BEGIN and END
  1557. BEGIN and END are two special kinds of patterns which are not tested against the input.
  1558. The action parts of all BEGIN patterns are merged as if all the statements had been
  1559. written in a single BEGIN block. They are executed before any of the input is read.
  1560. Similarly, all the END blocks are merged, and executed when all the input is exhausted
  1561. (or when an exit statement is executed). BEGIN and END patterns cannot be combined
  1562. with other patterns in pattern expressions. BEGIN and END patterns cannot have
  1563. missing action parts.
  1564.  
  1565.     BEGIN {FS = ",[ \t]*|[ \t]+"}
  1566. sets the field separator to either a comma followed by optional blanks and tabs or
  1567. one or more blanks and tabs—a common field separator in a real database.
  1568.  
  1569.  END blocks are often used to finish up after all the input has been seen, as in this
  1570.  little program:
  1571.              {out[++n] = $0}
  1572.     END {for (i = n; i >= 1; --i) print out[i]}
  1573. which accumulates all input records in the array “out”, and then at the end
  1574. prints out the records in reverse order.
  1575.  
  1576.     Expressions as patterns
  1577. Simply put, an expression is any sensible combination of variables, operators, and
  1578. (rarely) function calls. When an expression used as a pattern evaluates to a non–zero or
  1579. non–null result, the action following it will be carried out.
  1580.  
  1581. The most common sort of expression used as a pattern is the comparison, involving the
  1582. operators ==, <=, >=, >, <, and !=.  These can be used with any hAWK variable or
  1583. calulated result, and it is a refreshing improvement over C to be able to test
  1584. two strings for equality with the simple “a == b” instead of “!strcmp(a,b)”.
  1585.  
  1586. Comparison patterns quite often involve tests on the current input, such as
  1587. “$1/$2 >= 100”, “$3 == "Wilhelmina"”, “$0 != ""”, the last testing that
  1588. the current input line is not empty. Built–in variables are also popular, as in
  1589. the “FNR == 1” example a few paragraphs above, which detects the start of an
  1590. input file. Your own variables can of course appear, as in
  1591.     $1 != lastFieldOne    { print "New field one is", $1
  1592.                                         lastFieldOne = $1
  1593.                                     }
  1594. which prints the contents of the first field on the input line whenever it changes.
  1595.  
  1596. In a comparison, if both sides are numeric then the comparison is made numerically,
  1597. but if one side evaluates to a string then the comparison is done in terms of strings,
  1598. with the other side first being converted if necessary to a string.
  1599.  
  1600.     String-matching patterns
  1601. The matching operator, denoted by a tilde (~), allows you to detect whether one string
  1602. contains another string, though technically that other string is treated as a “regular
  1603. expression”. More on regular expressions in just a minute, but for now you can form a
  1604. regular expression to look for from a string of characters by putting a forward slash
  1605. before and after them. For example, if you wish to determine if the current input line
  1606. contains the string "exception", then the pattern
  1607.     $0 ~ /exception/
  1608. will do it. Note that it could match the line
  1609.     "while this is not an exceptional case, there are other"
  1610. that is, the match does not have to be an entire word.
  1611.  
  1612. By default if you omit the string for the matching operator to check against, and further
  1613. omit even the matching operator, leaving just the regular expression enclosed in slashes,
  1614. then the match will be done against the current input line $0. In other words,
  1615.     /regular expression/ {action}
  1616. is the same as
  1617.     $0 ~ /regular expression/ {action}
  1618. —and since even the action is optional (recall the default is to print $0), about the shortest
  1619. hAWK program you can write is
  1620.     /a/  #equivalent to   $0 ~ /a/ { print $0 }
  1621. which will print any input line containing an “a” to stdout.
  1622.  
  1623. To match punctuation explicitly in your expression you should precede it with a
  1624. backslash, eg /question\?/, /the end of the sentence\./, /array\[index\]/.
  1625.  
  1626. You can use quotes instead of the forward slashes to surround the text of your regular
  1627. expression with the same results. In this case, though, the matching operator must
  1628. explictly appear. Eg
  1629.     $0 ~ "Mars" {print "red planet detected on input line", FNR}
  1630. And to match punctuation explicitly inside the quotes, you should precede the punctuation
  1631. with two (that’s right, two) backslashes. For example, to match "the end." use
  1632.     string ~ "the end\\."
  1633.  
  1634. Using forward slashes instead of quotes around your regular expression has three small
  1635. advantages; matching against $0 doesn’t need to be fully written out, only single escapes
  1636. are necessary to match punctuation, and after a while the forward slashes will stand out
  1637. as you read your programs, signalling a matcher.
  1638.  
  1639. The negation of the matching operator, “!~”, allows you to determine if a string does
  1640. not contain some regular expression, as in
  1641.     $2 !~ /A/ {print "Error, second field does not contain the letter A"}
  1642. and any points mentioned above for ~ apply to !~.
  1643.  
  1644.     Regular expressions
  1645. Regular expressions aren’t as hard to use as a first impression suggests, and if you try
  1646. out a dozen you’ll be hooked, guaranteed. In regular expressions certain characters
  1647. have special “powers” that allow you to search for entire related groups of strings
  1648. with a single specifying string. Consider that an ordinary “find” command will not let
  1649. you completely match the following variations of a string: plurals; possessives;
  1650. variable blanks, tabs and especially returns between the words of a string; one or more
  1651. alternate words in the string; the complete word that contains some special substring;
  1652. two or more complete strings at once (one or the other).
  1653.  
  1654. A regular expression is nothing more than a string of text with optional special
  1655. “metacharacters”, and in most cases the string to be used can result from
  1656. the evaluation of a variable, or the concatenation of several strings or variables.
  1657. This means you can build the regular expressions for your program during the
  1658. execution of your program, modifying them on the fly to suit changing circumstances.
  1659.  
  1660. Parts of a regular expression can be grouped (with ordinary parentheses), and later in
  1661. the regular expression or in a replacement string can be referred to by the group “tags”
  1662. \1, \2, ... \9 where \1 refers to the group started by the first left parenthesis, \2 to
  1663. the second, etc. These allow you to match a small pattern within the context of a larger
  1664. one, detect duplicate expressions, change the order of the groups and so on. Note that
  1665. parentheses have the highest precedence of all regular expression “operators”, so
  1666. they serve two purposes; changing the order in which the metacharacters apply, and
  1667. marking the boundaries of a group, for later reference via \1..\9. More on this in a bit.
  1668.  
  1669. Regular expressions are built from ordinary characters,  the escape sequences
  1670.     \t  \n  \b  \B  \w  \W  \<  \>  \1  \2  \3  \4  \5  \6  \7  \8  \9
  1671. and from the metacharacters
  1672.             \ ^ $ . [ ] | ( ) * + ?
  1673. which are the ones with the special powers mentioned above. As you saw in the above
  1674. section, if a regular expression contains no metacharacters then it behaves like an
  1675. ordinary “find” string in that each character in the regular expression must match
  1676. a character in the string being searched. The following table summarizes all
  1677. character usage in a regular expression (where a b c are ordinary characters,
  1678. m is a metacharacter, r is a regular expression, and d is a digit):
  1679.  
  1680. c                matches the non-metacharacter c itself
  1681. \m            matches the literal character m, eg \$ matches the dollar sign.
  1682. .                matches any single character except newline.
  1683. ^                matches the beginning of a line or a string.
  1684. $                matches the end of a line or a string.
  1685. [ abc... ]    character class, matches any one of the characters    a or b or c etc... .
  1686. [^ abc... ]    negated character class, matches any character except    abc... and newline.
  1687.                 (Ranges of characters may be abbreviated in character classes, as in
  1688.                 [0-9] which matches any digit, [A-Za-z] which matches any letter,
  1689.                 [^0-9] which matches anything but a digit).
  1690. \w            matches a “word” character, exactly equivalent to [0-9A-Za-z]
  1691. \W            matches a non-word character, ie [^0-9A-Za-z]
  1692. \<                matches the beginning of a word.
  1693. \>                matches the end of a word.
  1694. \b                matches the beginning or end of a word (a word boundary).
  1695. \B            matches the boundary (beginning or end) of a set of non-word characters.
  1696. \t                matches a tab.
  1697. \n                matches a newline (the Return key).
  1698. r1 | r2    alternation: matches either r1 or r2, eg "blue|green"
  1699. r1r2        concatenation: matches r1 followed by r2 .
  1700. r +            matches one or more r 's. 
  1701. r *            matches zero or more r 's.  (Note that zero r’s can be anywhere in the text)
  1702. r ?            matches zero or one r 's. 
  1703. ( r )        grouping: matches r. Parentheses have two distinct uses; to override
  1704.                 default precedence of metacharacter operators, and to tag a subexpression
  1705.                 for subsequent reference. 
  1706. \1...\9        stand for whatever text the first through ninth set of parentheses currently
  1707.                 match, counting opening parentheses from left to right. Note that if the
  1708.                 pair of parentheses has a + or * or ? operator after it, then all of the
  1709.                 matches are included, eg /(foo)+bar/ applied to "foofoofoobar" will set
  1710.                 \1 to  "foofoofoo". To get just the first foo, use /(foo)\1*bar/ - then
  1711.                 \1 is set to "foo". (Perl users note this is the opposite of what
  1712.                 you are used to).
  1713. \ddd            is interpreted as an octal number, as in C. The digits exclude 8 and 9,
  1714.                 needless to say, and there can be from 1 to 3 digits in the number.
  1715.                 Note that \1 through \7 are interpreted as subexpression tags unless
  1716.                 followed immediately by another octal digit (eg \23 is not tag 2 followed
  1717.                 by a 3, it is the octal number 19 decimal). \8 and \9 are always tags,
  1718.                 since 8 and 9 are not octal numbers. To refer to octal numbers 1 to 7,
  1719.                 use \01 to \07. To follow a tag with a low number (eg \2 followed by 3),
  1720.                 use the octal representation of the number (eg \2\063 -- \063 equals
  1721.                 51 decimal, the ASCII code for 3).
  1722.  
  1723. The metacharacters ^ and $ to match the beginning and end of strings, and
  1724. \b \B \< \> to match various boundaries don’t actually match any characters;
  1725. rather they force alignment to a particular text position. For example,
  1726. /\brun\b/ will always match just “run” if it matches anything, but will
  1727. not match "runner" or "brunt". By comparison, /\Wrun\W/ won’t match
  1728. “runner” or “brunt” either, but it will include any non–word character that
  1729. happens to come before or after the word “run”. Normally you won’t want to
  1730. include leading or trailing spaces etc in the match.
  1731.  
  1732. Parentheses () have the highest precedence, allowing you to override default
  1733. precedence when needed. The “repetition” operators * + ? have the next–highest
  1734. precedence, followed by concatenation, with alternation having the lowest precedence of
  1735. all. For example, in abc*d the * applies only to the c since the repetition operator acts
  1736. before concatenation, and in abd|def the | applies to abd and def since concatenation
  1737. binds them together into little groups of three before alternation can play.
  1738.  
  1739. Regular expression can be used to just locate an instance of a pattern, as in
  1740.     $0 ~ /extern/
  1741. but they can also be used to specify text for replacement, by using the “sub” and
  1742. “gsub” functions. Looking ahead just a bit, these functions take a regular expression as
  1743. the first argument, the string to use for replacement as the second argument, and the
  1744. string to do the search and replace in as the third argument, with $0 used by default if
  1745. there is no third argument. “sub” does a single substitution on the text, and “gsub”
  1746. does all possible non-overlapping substitutions. Within the replacement strings of
  1747. these functions, you can use \1 through \9 to refer to text currently matched by tagged
  1748. subexpressions, and the ampersand “&” stands for all of the text that was matched.
  1749. To put a plain ampersand in the replacement, use “\&”.
  1750.  
  1751. At this point some considerable exampling usually helps:
  1752. The quick brown                    matches just that, "The quick brown". Note it would match
  1753.                                             "The quick brown" in "The quick brownie".
  1754. red fox\.                                matches "red fox." (the period must be escaped for a literal match).
  1755. [ \t]                                        matches a single space or tab ( that’s a space before the \).
  1756. [ \t]+                                    matches any consecutive run of spaces and tabs in any mix.
  1757. [0-9]+                                matches an integer (read “one or more digits”)
  1758. [+-]?[0-9]+                        matches an integer, together with optional preceding sign.
  1759. \<[A-Za-z'’-]+\>                matches an English word.
  1760. houses?                                matches "house" or "houses".
  1761. m(iss)*ippi                        matches "mippi", "missippi", "mississippi", "missississippi", etc.
  1762. ar*g                                        matches "ag", "arg", "arrg", "arrrg", etc.
  1763. MyFunction\(                        matches "MyFunction(".
  1764. array\[index\]                    matches "array[index]".
  1765. array\[.+\]                            matches "array[i]", "array[j]", "array[2*q-1]", etc.
  1766. \\([0-7]|[0-7][0-7])        matches "\d" or "\dd" where d is an octal digit.
  1767. ([^\\]?|(\\\\)+)"                (horrors, be brave) matches an unescaped quote or a quote
  1768.                                             preceded by an even number of backslashes—in other words
  1769.                                             a true quote in C. The backslash is a metacharacter, so matching
  1770.                                             one literally requires a backslash before the backslash.
  1771. The[ \t]+quick[ \t]+brown    matches "The quick brown" with variable spaces and tabs
  1772.                                             between the words.
  1773. \/\*                                        matches the start of a C comment, "/*". The forward slash is
  1774.                                             escaped so that you can place the whole regular expression inside
  1775.                                             forward slashes. The escape before '/' would not be needed if you
  1776.                                             placed the expression inside quotes, but then you would need two
  1777.                                             escapes before the '*', ie "/\\*".
  1778. \/\*.*\*\/                            matches all of a one–line C comment, "/* - anything - */".
  1779. ^Z                                            matches a 'Z' at the beginning of a string.
  1780. ^.                                            matches the first character of a string.
  1781. .$                                            matches the last character of a string.
  1782. ^.*$                                        matches any string completely (not much use).
  1783. ^A..$                                    matches any string which is three characters long, the first
  1784.                                             being an 'A'.
  1785. ^(A|B).*                                matches all of any string that begins with 'A' or 'B'.
  1786. ^[AB].*                                does likewise.
  1787. (\w|_)\w*                            matches a C term, or integer constant.
  1788. ((->)|(\.))(mem\b)            matches “mem” when it is immediately preceded by “->”
  1789.                                             or “.”, and is not the beginning of a longer word. For
  1790.                                             replacement purposes in a “sub” or “gsub”, the part
  1791.                                             before “mem” is given by \1, and mem itself is \4.
  1792. gsub(/((->)|(\.))(mem\b)/, "\1\4ber") will turn “->mem” into “->member”
  1793.                                             and “.mem” into “.member” everywhere in the current
  1794.                                             input line $0, ignoring things like “remember” or
  1795.                                             “->memories”.
  1796. gsub(/\bFuncName([ \t]*\()/, "FunctionName\1")    will replace “FuncName” by
  1797.                                             “FunctionName” everywhere in the current input line
  1798.                                             $0, provided it is followed on the same line by an opening
  1799.                                             parenthesis, with optional spaces or tabs between the name
  1800.                                             and “(”. The match extends from the “F” of 
  1801.                                             “FuncName” up to and including the “(”, so the “(”
  1802.                                             and any intervening white space must be put back into
  1803.                                             the replacement string by tagging them in parentheses
  1804.                                             and using \1 after “FuncName” to refer to what was
  1805.                                             matched by the first set of parentheses in the pattern.
  1806.  
  1807. This program prints all input lines containing one-line comments:
  1808.         /\/\*.*\*\//        {print}
  1809. (since {print} is the default action, it could be left out).
  1810.  
  1811. Within a character class most metacharacters are taken literally. The exceptions are
  1812. the escaping backslash \, the negating ^ (only at the beginning), and the range hyphen -
  1813. (only between two characters). For example,
  1814.         [A-Za-z-]        matches an English word, hyphens included
  1815.         [-A-Za-z]        does the same
  1816.         [\-A-Za-z]        also does the same (the '\' is unnecessary but harmless)
  1817.         ^[^^]                matches any single character that is not a '^' at the beginning of a string
  1818.         [\^]                    matches a '^'.
  1819. The toughest metacharacter to remember is the '^' which has three meanings: at the beginning
  1820. of a character class it signals a negated character class; outside of a character class it matches
  1821. the beginning of a string; and when escaped or not the first character in a character class it
  1822. matches a literal '^'.
  1823.  
  1824. Regular expressions are “left greedy”; where there could be more than one match in a
  1825. string, a regular expression matches the leftmost one, and extends the match as far as
  1826. possible. For the implications of this, see the discussion of the “match” operator in the
  1827. “Built–in string and file functions” section of the next chapter, “Actions”.
  1828.  
  1829. Now that we’re starting to get the hang of things, more examples using the replacement
  1830. functions “sub” and “gsub” mentioned above. The format is sub(r,s,t) where r is a
  1831. regular expression, s is the replacement string, and t is the string in which the search
  1832. and replace is to be done. The contents of t before and after the sub are spelled out below.
  1833.  
  1834. using t = "Don’t run that prune over, runt!":
  1835. sub(/run/, "fly", t)                turns t into "Don’t fly that prune over, runt!"
  1836. gsub(/run/, "fly", t)                turns t into "Don’t fly that pflye over, flyt!"
  1837. gsub(/\brun\b/, "fly", t)        turns t into "Don’t fly that prune over, runt!"
  1838. gsub(/run/, "t&k", t)        turns t into "Don’t trunk that ptrunke over, trunkt!"
  1839. using t = "#define FOO        1":
  1840. sub(/#define\W+(\w+)\W+([0-9]+)/, "int \1 = \2;",t) turns t into
  1841.         "int FOO = 1;" (\W+ means one or more non-word characters, \w+
  1842.         means one or more word characters, [0-9]+ means one or more digits;
  1843.         two groups are tagged).
  1844.  
  1845. Three programs are supplied to help you do general–purpose listing of matches or
  1846. search–and–replace; $MFSLister searches for either plain text or a regular expression
  1847. with “Set variables” in the setup dialog, and lists file name/ line number of all
  1848. single–line matches to stdout; $MFS_SuperLister does much the same, but finds
  1849. matches that span a variable number of lines; and $MFS_SuperReplace does the
  1850. ultimate search and replace, matching either plain text or full–blown regular
  1851. expressions over a variable number of lines, handling any number of files at once,
  1852. documenting the (post–change) locations of all changes to stdout. Heck, it even prints
  1853. the fragments of original text before the changes, so that if you mess up you can at least
  1854. (manually) undo the damage. (Exercise: write $MFS_Undo_SuperReplace).
  1855.  
  1856.     Compound patterns
  1857. The logical operators ||, &&, and ! can be used to combine simple patterns into compound ones.
  1858. These operators function the same as in C, specifically: || is the inclusive–or operator; && is
  1859. the and operator; and ! is negation, with evaluation of a compound pattern proceeding only as
  1860. far as necessary to determine whether the whole pattern is true or false.
  1861.  
  1862. Some examples:
  1863.     $1 ~ /DATA/ && $2+0 > 0
  1864. is true when the first field contains the string "DATA" and the second field is numeric and
  1865. greater than zero. If the first field does not contain "DATA" then the second field is not checked.
  1866.     $1 == "DATA" || $1 == "INFO"
  1867. is true when the first field is exactly equal to "DATA" or "INFO". The check for "INFO" is
  1868. performed only if the check for "DATA" fails.
  1869.     $2 != 0 && !($3/$2 > 10 || $3/$2 < 1)
  1870. first checks that $2 is not zero, to avoid dividing by zero, and then evaluates to true if
  1871. $3 divided by $2 falls in the range 1 to 10.
  1872.  
  1873. The ? : operator can be used to choose between two patterns, and is like the same
  1874. operator in C. If the first pattern is true then the pattern used for testing is the second
  1875. pattern, otherwise it is the third. Only one of the second and third patterns is evaluated.
  1876.  
  1877.     $2 != 0 ? $3/$2 > 1 : $3 == 0
  1878. first checks to see if field 2 is non–zero; if so, the pattern is true if $3/$2 > 1; otherwise,
  1879. the overall pattern is true if field 3 is also zero.
  1880.  
  1881.     Range patterns
  1882. Range patterns consist of two patterns separated by a comma. Given
  1883.     pattern1, pattern2
  1884. this evaluates to true for the first input line that matches pattern1, and thereafter is
  1885. true up to and including the first line encountered that contains pattern2. Both patterns
  1886. may occur on the same line, in which case the range pattern is true for just the one
  1887. line (and a check for pattern1 begins again on the next line). If the second pattern is
  1888. never seen, matching continues to the end of all input. Range patterns, as with BEGIN
  1889. and END, cannot be compounded with other patterns to form more complicated patterns.
  1890.  
  1891. Note that pattern2 specifies the last line to be matched, for example
  1892.         NR == 1, NR == 2
  1893. matches the first and second lines of input. 
  1894.  
  1895. Range patterns are useful only with input that has been well–organised on a line–by–line
  1896. basis, with clear signals for the start and end of a group of lines. An ideal case would be
  1897. a file with markers dedicated to indicating the start and end of a group, such as
  1898.         Start 10 11 -23
  1899.         47 101 96 End
  1900.         Start 19 23 End etc
  1901. in which case your program could analyze groups with
  1902.         /Start/, /End/    {actions for the group}
  1903. but in real life the only way you’ll see an input file like this is if you make it yourself.
  1904.  
  1905.     Summary of patterns
  1906. A list of beasts in the pattern zoo (regex stands for regular expression, pat
  1907. stands for pattern, str stands for string variable):
  1908. Pattern                                        Example
  1909. ----------------                -------------------------------
  1910. BEGIN                                            BEGIN blocks are done before all input
  1911. END                                                END blocks are done after all input
  1912. /regex/                                        /Mary( \t)+had/
  1913. str ~ /regex/                                (or !~)    $1 ~ /(\-)?[0-9]+/
  1914. str ~ "regex"                                (or !~)    $1 ~ "(\\-)?[0-9]+"
  1915. relational expression                    NF > 4
  1916. pattern && pattern                        FNR == 1 && /File title:/
  1917. pattern || pattern                        /Vermont/ || /Maine/
  1918. pattern ? pattern : pattern            $3 != 0 ? $2 / $3 > 25 : $2 < 0
  1919. ( pattern )                                    - see next line
  1920. ! pattern                                        !($0 == "" || $0 ~/^The end$/) 
  1921. pattern1 , pattern2                    FNR == 5, FNR == 8
  1922.  
  1923. There’s no substitute for doing it yourself. Here’s a small program that will let
  1924. you try out your own patterns—it’s not saved separately, so select it and save it
  1925. into your “hAWK programs” folder under a name that begins with a '$', such as
  1926. “$PatternTester”. Substitute your test pattern for the word “pattern” below
  1927. when you have one to try out. Grab some example input from somewhere, paste it
  1928. into a new window, call hAWK, select “$PatternTester”, and run it with the
  1929. “All of front text” input option, leaving “Show stdout” with a check mark. All input
  1930. lines that match your pattern will produce a comment in stdout, which will be shown
  1931. to you after the run.
  1932.  
  1933. #A small program for testing patterns.
  1934. #Replace the word "pattern" on the next line with your pattern.
  1935. pattern        {
  1936.                         print "Pattern matched input line", NR, "which was:"
  1937.                         print "\t", $0
  1938.                         ++n
  1939.                     }
  1940. END                {    if (n > 0)
  1941.                             print "Total matches:", n;
  1942.                         else
  1943.                             print "No matches were found.";
  1944.                     }#the end
  1945.  
  1946. -------
  1947.     Actions
  1948. -------
  1949.     Introduction
  1950. Virtually everything you have learned about patterns can be carried over to actions for
  1951. constructing conditional tests (excepting BEGIN, END, range patterns, and default
  1952. behaviour when parts of a pattern are left out). For example,
  1953.     $1 ~ /NUM/    {if ($2 ~ /RANGE/)
  1954.                                 --then the first field contained "NUM", and the 
  1955.                                 second field contained "RANGE"--
  1956.                             }
  1957. or
  1958.     FNR < 10    {if (FNR == 1)
  1959.                         print "First line of current file is:", $0
  1960.                     else if (FNR == 2)
  1961.                         print "Second line of current file is:", $0
  1962.                     etc
  1963.                     }
  1964. which demonstrate that it is possible to place a general test in the pattern, and then proceed
  1965. with more specific tests in the action statements.
  1966.  
  1967. You’ve probably noticed that hAWK expressions strongly resemble C code, and this is
  1968. no accident—leaving aside the advanced machinery of C dealing with pointers, structs
  1969. and unions, and multi–dimensional arrays, what you know about writing C carries over
  1970. to hAWK. There are some omissions, such as no need to declare variables, no prototypes
  1971. for functions, no brackets around the arguments of some built–in functions (print,
  1972. getline) that require a bit of adjustment. And there are some additions (most notably
  1973. regular expressions, built–in string functions such as “match”, and the way input is
  1974. automatically retrieved to $0) which require a bit of work to grasp comfortably. But
  1975. regular expressions were the only tough part; the rest is easy by comparison, and
  1976. you should count your hAWK diploma as a foregone conclusion if you keep going here.
  1977.  
  1978. You have met variables, including built–in and field variables, and the operators which
  1979. are especially useful for building patterns: the sections below will round out the list of
  1980. operators, describe hAWK’s built–in functions dealing with numbers and strings, and
  1981. introduce control–flow statements (if, for, while, etc) which allow you to choose between
  1982. alternatives or repeatedly excute statements.
  1983.  
  1984. Knowledge of C will speed up learning hAWK. However, hAWK is simpler than C, so if you
  1985. are new to C as well you should find that learning hAWK will speed up learning C. Whatever
  1986. your background, you should regard hAWK itself as an essential part of this manual; if you
  1987. have a small problem, or an idea that wants polishing, whip up a little hAWK program and
  1988. give it a try.
  1989.  
  1990.     A preview of “print”
  1991. Ultimately, your hAWK program will produce output. The “print” statement will answer
  1992. most all of your output needs, being simpler in form than the “printf” function which has
  1993. more sophisticated formatting. Pass “print” a list of variables or constants separated by
  1994. commas, and they will be printed to stdout, with the commas replaced by the output field
  1995. separator (the built–in variable OFS, by default a blank). The contents of ORS (the output
  1996. record separator, by default a newline) will be appended to the end of what was printed.
  1997.  
  1998. For example:
  1999. this one–line program
  2000.     {print FNR, $0}
  2001. will duplicate all input to stdout, adding a line number to the beginning of each line. The
  2002. number will be reset to 1 at the beginning of each input file, but all input files will be
  2003. concatenated together in stdout.
  2004.     {print $1}
  2005. will print just the first field of each input line to stdout.
  2006.     $1 ~ /extern/ {print FILENAME, FNR}
  2007. will print the (full path) file name and line number where the word “extern”
  2008. was seen.
  2009.  
  2010. Variables and strings may be concatenated together by using a space instead of a comma
  2011. between them, for example
  2012.     a = "Sesqui"
  2013.     b = "alien"
  2014.     print a "ped" b
  2015. which produces "Sesquipedalien" (note there is no built–in spelling checker). Concatenation
  2016. is slower than using commas to separate the items for “print”, best used only if you must
  2017. avoid having the OFS space between two items. Note that
  2018.     print a, "ped", b
  2019. produces "Sesqui ped alien".
  2020.  
  2021. More on “print” later, but for the time being if you find yourself wondering what an
  2022. operator or function produces—assign the result to a variable and print it out.
  2023.  
  2024.     Expression operators
  2025. With the exception of string concatenation and the matching operators, the operators in
  2026. hAWK are the same as C operators. They apply to both numbers and strings wherever it
  2027. is logical, and that numbers are floating point numbers. Note that if a variable is
  2028. assigned an integer value then it can be treated as an integer—for example, if
  2029.     i = 1                at some point, then later the test
  2030.     if (i == 1)         will evaluate to true (non-zero), with no failure due to obscure
  2031. floating point rounding trouble.
  2032.  
  2033. The operators in hAWK, in order of increasing precedence, are:
  2034. --------------------------------------------
  2035. =         +=     -=     *=     /=     %=     ^=
  2036. Assignment. Both absolute assignment ( var " = " value ) and operator-assignment (the
  2037. other forms) are supported. “a += b” is equivalent to “a = a + b”.
  2038.  
  2039. ?:                The C conditional expression. This has the form
  2040.                 expr1 " ? " expr2 " : " expr3
  2041. If expr1 is true, the value of the expression is expr2 , otherwise it is expr3 . Only one
  2042. of expr2 and expr3 is evaluated.
  2043.  
  2044. ||                logical OR. In “a || b” if a is true then b is not evaluated.
  2045.  
  2046. &&            logical AND. In “a && b” if a is false then b is not evaluated.
  2047.  
  2048. ~ !~            regular expression match, negated match. See “String-matching patterns”.
  2049.  
  2050. < <= > >= != ==
  2051.                 the regular relational operators. Note especially that strings can be
  2052.                 compared, eg if ($3 == "cat"). In “a <= b” or the like, if both
  2053.                 arguments are numbers the comparison is done numerically,
  2054.                 otherwise they are compared as ASCII strings.
  2055.  
  2056. blank        string concatenation;  if a = "John" and b = "Henry" then
  2057.                 c = a b; produces c = "JohnHenry".
  2058.  
  2059. +  -            addition and subtraction.
  2060.  
  2061. * / %        multiplication, division, and modulus (  x%y produces the remainder of
  2062.                 x divided by y, equivalent to x - int(x/y)*y  ).
  2063.  
  2064. +  - !        unary plus, unary minus, and logical negation.
  2065.  
  2066. ^                exponentiation.
  2067.  
  2068. ++  --    increment and decrement, both prefix and postfix.
  2069.  
  2070. $                field reference. $0 is the entire current record, $1 the first field,
  2071.                 and $NF the last field. Fields may be changed or added.
  2072.  
  2073. Some examples:
  2074.     {lines[++n} = $0}
  2075. accumulates all input lines to the array lines[]. The variable “n” starts out as 0, so
  2076. the “++n” produces 1 as the first index. At the end of input “n” is equal to the number
  2077. of input lines seen, so
  2078.     END {print lines[1]; print lines[n]}
  2079. would print out the first and last lines of input.
  2080.  
  2081.  
  2082.     Built–in numeric functions
  2083. hAWK has the following pre-defined arithmetic functions, with x and y as
  2084. arbitrary expressions:
  2085. atan2( y , x )            returns the arctangent of y/x in radians.
  2086. cos( x )                    returns the cosine of x in radians.
  2087. exp( x )                    the exponential function "e to the x"
  2088. int( x )                    truncates to integer (eg int(7.325) gives 7); to round,
  2089.                                 use int(x + .5).
  2090. log( x )                    the natural logarithm function, base e. For log base 10, use
  2091.                                 log(x)/log(10).
  2092. rand()                        returns a random number, 0 <= rand() < 1.
  2093. sin( x )                    returns the sine of x in radians.
  2094. sqrt( x )                    the square root function.
  2095. srand( x )                use    x    as a new seed for the random number generator. If no
  2096.                                 x is provided, the time of day will be used. The return value
  2097.                                 is the previous seed for the random number generator.
  2098.  
  2099. Some examples:
  2100.     atan2(0,-1) gives π, and exp(1) gives e.
  2101.     
  2102.     theta = atan2(y,x)
  2103.     r = sqrt(x*x + y*y)
  2104. converts rectangular x,y to polar r,theta.
  2105.  
  2106.     int(max * rand())
  2107. produces a random integer from 0 to max-1, inclusive.
  2108.  
  2109.     Built–in string and file functions
  2110. There is only one string operator, the concatenation operator, invoked when two variables
  2111. or constants are separated by a space. Other useful string manuipulations in hAWK are
  2112. carried out by built–in functions. In the following table, r is a regular expression,
  2113. s and t are strings, the a and b are arrays, and i and n are integers.
  2114.  
  2115. gsub(r, s, t)        for each substring matching the regular expression r in
  2116.                             the string t , substitutes the string s , and returns the
  2117.                             number of substitutions. If t is not supplied, uses $0 .
  2118. index( s ,  t )        returns the index of the string t in the string s,
  2119.                             or 0 if t is not present.
  2120. length( s )            returns the length of the string s .
  2121. match( s , r )        returns the position in s where the regular expression r
  2122.                             occurs, or 0 if r is not present, and sets the values of
  2123.                             RSTART and RLENGTH .
  2124. split(s, a, r)        splits the string s into the array a on the regular
  2125.                             expression r , and returns the number of fields. If r is
  2126.                             omitted, FS is used instead.
  2127. sprintf( fmt , expr-list )        prints expr-list according to fmt , and returns the
  2128.                             resulting string. See the discussion of “printf” for details.
  2129. sub(r, s,t)             this is just like gsub , but only the leftmost matching
  2130.                             substring is replaced. Returns number of substitutions.
  2131. substr(s, i, n)    returns the n-character substring of s starting at i . If n
  2132.                             is omitted, the rest of s is used.
  2133. tolower( s )        returns a copy of the string s , with all the uppercase
  2134.                             characters in s translated to their corresponding
  2135.                             lowercase counterparts. Non-alphabetic characters are
  2136.                             left unchanged.
  2137. toupper( s )        returns a copy of the string s , with all the lowercase
  2138.                             characters in s translated to their corresponding
  2139.                             uppercase counterparts. Non-alphabetic characters are
  2140.                             left unchanged.
  2141. lookup( s )            returns integer–coded C type of s (s should be a word).
  2142.                             (At present this function is supported by: EnterAct.
  2143.                             Types are taken from whatever project is open at the
  2144.                             time.) See “$LookupTest” or “$XRef” for an example.
  2145.                             Type                                                    integer returned
  2146.                             ----                                                ------------
  2147.                             defined constant or macro                1
  2148.                             file–scope variable                            2
  2149.                             function                                            4
  2150.                             enum constant                                    8
  2151.                             typedef                                                16
  2152.                             struct tag                                            32
  2153.                             union tag                                            64
  2154.                             enum tag                                            128
  2155.                             other                                                0
  2156. sort(a,b,s)            produces an index in the array “b” that can be used to access
  2157.                             the elements of “a” in sorted order. The string “s” specifies the
  2158.                             kind of sort; "a" for ASCII, "n" for numeric, "d" for dictionary
  2159.                             order, and "ra", "rn", "rd" for reverse of the same. Returns the
  2160.                             number of elements in the array “b”, which is indexed numerically
  2161.                             from 1 upwards. The elements of “b” are the indexes of “a” in
  2162.                             sorted order provided “b” is accessed in the sequence b[1], b[2],
  2163.                             b[3] etc. Typical use is
  2164.                                 maxIndex = sort(a, b, "d")
  2165.                                 for (i = 1; i <= maxIndex; ++i)
  2166.                                     print a[b[i]]
  2167.                             which will print the elements of a in sorted dictionary order.
  2168.                             See “$WordFrequency” and “$XRef_Full” for examples, and
  2169.                             “$SortTest_Nums” for a simple numeric example.
  2170. time( )            returns the current time, eg "Sunday, October 27, 1991 09:03:30 AM"
  2171.                         —note this is the time when the function is called, down to the second,
  2172.                         whereas the TIME variable holds the time at which your program run
  2173.                         starts, down to the minute. See “$TIME” for an example.
  2174. prompt( s )        displays an OK/Cancel dialog. The string “s” appears at the top of the
  2175.                         dialog, and you can type in a string in an edit field. Returns what you
  2176.                         type in, as though it was a string constant. Both the string “s” and what
  2177.                         you type in are limited to 255 characters. For an example of usage
  2178.                         see “$PromptTest” and “$YoungMath”. Typical use is
  2179.                             x = prompt("Enter the number of lines to print:")
  2180.                             if (x+0 > 0) {
  2181.                                 while (getline lne > 0 && ++i <= x) print lne }
  2182.                         If you cancel the dialog or hit <Return.> without typing in any text,
  2183.                         prompt returns the null string "".
  2184.                         NOTE this function is only useful if hAWK is called up in the “immedate”
  2185.                         mode (typically hold down the <Shift> key when selecting “hAWK”). In
  2186.                         “concurrent” mode, “prompt()” does nothing but return the empty
  2187.                         string "" without displaying a dialog.
  2188. progress(s)    displays the string “s” in a dialog on your screen (the message stays
  2189.                         on the screen). You can change the message with another “progress”
  2190.                         call.  “progress” returns the number of times it has been called, and
  2191.                         the dialog goes away by itself at the end of your program run. For a
  2192.                         test sample, see “$ProgressTest”.
  2193.                         NOTE this function is only useful if hAWK is called up in the “immedate”
  2194.                         mode (typically hold down the <Shift> key when selecting “hAWK”). In
  2195.                         “concurrent” mode, “progress()” does nothing but return 0.
  2196. --and added for hAWK version 2 (mainly file functions):
  2197. Note in the functions below where a file or directory name is required it must
  2198. be a full pathname, of the form “disk:folder1:folder2:...:folderN:filename”
  2199. for a file, or “disk:folder1:...:folderN” or “disk:folder1:..:folderN:”
  2200. for a directory (the second version has a colon at the end). For a disk name,
  2201. use “disk:” rather than “disk”.
  2202. beep( n )            does a SysBeep(n); if the duration "n" is <= 0, the menu bar will
  2203.                         flash instead. Durations of 0,1,2,5 work best.
  2204. copy( s, t )        copies the file named “s” to the file named “t”. Both file names
  2205.                         must be full pathnames (disk:folder:...folder:filename). Either
  2206.                         the location or name or both can be changed. If file “t” already
  2207.                         exists, it must be closed and unlocked. Both creator and type are
  2208.                         preserved, and  the resource fork is copied as well as the data
  2209.                         fork. Any kind of file can be copied. To move or rename a file, use 
  2210.                             if (copy(s,t)) remove(s)
  2211.                         (this is an efficient way to move a file, but there is a separate
  2212.                         rename() function). NOTE that t's folders will be created if needed.
  2213.                         Returns 1 if successful, 0 if the copy could not be done.
  2214. exists( s )        returns 1 if the file named “s” exists, 0 if it does not. Any kind
  2215.                         of file can be tested.
  2216. fdate( s )            returns date/time of last modification of file named “s”, format
  2217.                         “yr:mo:day:hr:min:sec” where yr is 4 digits, and the rest are 2
  2218.                         (eg always 01 rather than just 1). The length of the string is
  2219.                         always 19 (or 0 if no date could be extracted) and the colons
  2220.                         and digits always occupy the same positions.
  2221. fsize( s )            returns size in bytes of the data fork only of the file named “s”
  2222. getclip( n )        returns the calling application’s current clipboard text, up to
  2223.                         a maximum of the first “n” bytes. Use n = 0 or omit it entirely
  2224.                         if you want the entire clipboard. For example, if the current
  2225.                         clip is “Some text here” then getclip(6) returns “Some t”
  2226.                         whereas getclip(0) or getclip() returns the entire clip. At
  2227.                         present this function is supported by: EnterAct.
  2228. putclip( s )        replaces the calling application’s (private) clipboard with
  2229.                         the string “s”. Note that other applications won’t see the
  2230.                         change until you switch out of the calling app. The length
  2231.                         of s is limited to 32,767 characters (as are all hAWK strings).
  2232.                         See the “$Clip...” functions in the “hAWK programs” folder
  2233.                         for examples using getclip/putclip. Supported by: EnterAct.
  2234. list( s, a )        given file or directory full pathname in “s”, produces list of
  2235.                         full pathnames for all TEXT files in the directory (either the
  2236.                         directory named or the directory holding the file), as elements
  2237.                         indexed 1,2,3... in the array “a”. Note subdirectories are also
  2238.                         excluded. Returns the number of files in the list.
  2239. nested( s, a )    given a file full pathname in “s”, generates list of full pathnames
  2240.                         for directories at the same level ("sibling folders"); given directory
  2241.                         name, generates list of subdirectories at the top level in the named
  2242.                         directory (“offspring folders”). The list is returned as elements
  2243.                         indexed 1,2,3... in the array “a”. In other words, the same as
  2244.                         “list” but for folders rather than TEXT files. Note neither “list”
  2245.                         nor “nested” look beneath the top level of the folder in question.
  2246.                         Returns the number of directories in the list.
  2247. remove( s )        deletes the file named “s”, provided it is closed and unlocked. Use
  2248.                         with caution, this is not undoable unless you get lucky using your
  2249.                         favourite file recovery tool. Returns 1 if the file was deleted,
  2250.                         0 otherwise. Use with caution!
  2251. rename( s, t )    takes the file with full pathname “s”, and renames it “t”. The
  2252.                         new name “t” can be a full pathname, or just the new file name
  2253.                         proper, as in 
  2254.                             rename("Disk:dir1:aardvark", "Disk:dir1:fruitbat")
  2255.                         or equivalently
  2256.                             rename("Disk:dir1:aardvark", "fruitbat")
  2257.                         This function works only with files, not directories or volumes,
  2258.                         returning 1 if the rename was carried out, 0 if not.
  2259.  
  2260. The version 1 functions form the heart of hAWK, and you will find examples of usage of
  2261. one or more of these in nearly all the sample programs. The version 2 functions have
  2262. more limited scope, but keep them in mind when you need to wrestle with files.
  2263.  
  2264. Within the replacement string 's' of gsub(r,s,t) and sub(r,s,t), a '&' is taken to stand
  2265. for the entire string of text that was matched by the regular expression 'r'. For example,
  2266. gsub(/cat/, "&s", t)    with t = "cat and dogs" produces t = "cats and dogs" after
  2267. the substitution. Use “\&” if you want a literal '&' in the replacement string.
  2268.  
  2269. Using sub, gsub, and match effectively is entirely a matter of becoming comfortable
  2270. with regular expressions (practice makes perfect). The regular expressions in these
  2271. functions can be static, as in
  2272.     if (match($0, /struct/))...
  2273. or dynamic (the contents of a variable) as in
  2274.     wordStart = "^|[^a-zA-Z'-]"#beginning of string or non–word character
  2275.     optLetters = "[a-zA-Z'-]*"#zero or more word characters
  2276.     findString = wordStart "(A|a)ct" optLetters
  2277.     if (match($0, findString))...
  2278. (which matches eg “act”, “Actor” but not “tract”, or “Reactor”). It’s sometimes
  2279. handy to use the “Set variables” dialog to set the string to be found (see $MFSLister,
  2280. for example), or you can even read the string to be found out of the input itself, as in
  2281.     FNR == 1{find = $1; rep = $2}
  2282.     FNR > 1{gsub(find, rep)}
  2283. which sets the strings for find and replace from the first two fields on the first line
  2284. of input, and then uses them to do replacement on all subsequent lines.
  2285.  
  2286. A miscellany:
  2287.  
  2288.     {gsub(/->resourceid/, "->resourceID")
  2289.     gsub(/\.resourceid/, ".resourceID")
  2290.     }
  2291. copies all input to stdout, changing “resourceid” to “resourceID” when it appears
  2292. as a member name (note $0 is used in the gsub by default).
  2293.     
  2294.     gsub("\n", "\n", multi)
  2295. returns a count of the number of returns (newlines) in the string “multi”.
  2296.  
  2297.     gsub(/boo/, "&&s") turns “boo” into “booboos” everywhere in $0.
  2298.  
  2299.     index("abcdef", "cd") returns 3.
  2300.     
  2301.     match("abcdef", /cd/) returns 3, and sets RSTART to 3, RLENGTH to 2.
  2302.     
  2303.     z = split("hour:minute:second", arr, ":") assigns 3 to z, with
  2304. arr[1] = "hour", arr[2] = "minute", arr[3] = "second".
  2305.  
  2306.     Given str = "Now is the time",
  2307. substr(str,1,3) returns "Now", substr(str,8) returns "the time".
  2308.     
  2309. More examples follow the next section.
  2310.  
  2311.     Control-flow statements
  2312. Statements in hAWK may be grouped with curly braces, one can execute statements only
  2313. when a certain condition is met, and statements can be repeatedly executed according to
  2314. the value of some condition. While hAWK does not have a “goto”, it does allow you to
  2315. jump back to the top of your pattern–action statements with “next”, or jump to your
  2316. END statements on the way out the door with “exit”.
  2317.  
  2318. In the following list of control statments, any instance of “statement” can be replaced
  2319. by a group of statements enclosed in curly braces {}:
  2320.  
  2321. { statements }
  2322.     Simple grouping of several statements together, so that conditional or repeated
  2323.     execution can be applied to the group.
  2324. if (condition) statement1 [ else statement1 ]
  2325.     If the condition evaluates to true then statement1 is carried out; the “else”
  2326.     clause is optional, and its statements will be executed if the condition is false.
  2327. while (condition) statement 
  2328.     The condition is first evaluated, and if it is false then the statement is skipped. If
  2329.     it is true then the statement is executed; the condition is again evaluated, and the
  2330.     statements again executed if the condition is true, and this process continues until
  2331.     the condition is false. Note that if the condition is false the first time then the statement
  2332.     will not be executed at all. “while” loops are affected by break and continue statements.
  2333. do statement while (condition)
  2334.     The statement is always executed at least once; then the condition is evaluated, and if it
  2335.     is true then the statement is excuted again. This process continues until the condition
  2336.     is false. Unlike the “while” loop, the “do” loop always executes its statement at least
  2337.     once.
  2338. for (expr1; expr2; expr3) statement
  2339.     eg “for (i = 1; i <= 6; ++i) {print i}”
  2340.     Mnemonically, “for it’s (a jolly good fellow)” helps: in “it’s”, the “i” stands for
  2341.     initialization, the “t” for “test”, and the “s” for “step”. expr1 is the initialization,
  2342.      executed only once, just before the “for” loop proper is entered. Next
  2343.     expr2, the test, is evaluated, and if it is true then the statement is executed, otherwise
  2344.     the for loop ends and control passes to the next statement beyond it. If the statement is
  2345.     executed then expr3, the step, is carried out, and then it’s back to the top of the loop
  2346.     —no more initialization, but the sequence test, execute, step, continues until the test
  2347.     produces false.
  2348. for (var in array) statement
  2349.     Indexes for the array are retrieved one–by–one to the variable “var”, though not
  2350.     in a readily predictable order, and the statement is executed for each index.
  2351. break
  2352.     For use only among the statements that make up the body of a while, do, or for loop.
  2353.     Usually found in the form “if (condition) break;”, when the break is executed then
  2354.     control immediately passes to the next statement after the loop.
  2355. continue
  2356.     Also for use only in a while, do, or for loop, and also usually executed only when
  2357.     the condition of some if–statement is true. When encountered, control passes to the
  2358.     very end of the statements making up the body of the loop, and the next iteration of
  2359.     the loop begins.
  2360. next    
  2361.     Stop processing the current input record. The next input record is read and
  2362.     processing starts over with the first pattern in the hAWK program. If the end of
  2363.     the input data is reached, the END block(s), if any, are executed.
  2364. exit [ expression ]
  2365.     In an END action, exit truly causes the hAWK program to terminate. Anywhere
  2366.     else, the exit statement causes the program to jump to the END actions, and only
  2367.     if none are present does the program immediately terminate. The “expression”
  2368.     is provided for compatiblilty with standard AWK programs, and won’t be of any
  2369.     use to you.
  2370.  
  2371. Here’s a small sample program, with lots of potential if you’re looking for
  2372. a first hAWK project:
  2373.     BEGIN {    find = "(^|[^@])([A-Z][A-Z]+)" #note \1 \2 grouping by ()()
  2374.         rep["CA"] = "California"
  2375.         rep["HYPO"] = "hypobetalipoproteinemia"
  2376.         rep["RE"] = "regular expression"
  2377.         #...etc... note just a part of a word is OK
  2378.         }
  2379.     {loopCount = 0;
  2380.         while (match($0, find) && loopCount++ < 50)
  2381.             {
  2382.             acronym= substr($0, RSTART, RLENGTH)
  2383.             gsub(/[^A-Z@#]/, "", acronym) #or sub(find, "\2", acronym)
  2384.             if (acronym in rep)
  2385.                 sub(find, "\1" rep[acronym])#replace acronym by expansion
  2386.             else
  2387.                 sub(find, "\1@#@\2")#stick '@#@' in front of unknown acronym
  2388.             }
  2389.         if (loopCount >= 50)
  2390.             {
  2391.             print "The acronym", acronym, "is looping forever." ; exit
  2392.             }
  2393.         gsub(/@#@/, "")#trim the protector by replacing it with null string
  2394.         print #print the altered line to stdout
  2395.         }
  2396. - builds a glossary at the beginning, and then expands any acronyms in the input for
  2397. which there is an entry in the array “rep”, sending the expanded version to stdout.
  2398. The “sub” and “match” both match the leftmost longest string of uppercase letters,
  2399. and replacement is done one match at a time until the line contains no more matches.
  2400. To avoid an endless loop, finds for which there is no expansion have a '@#@' stuck in
  2401. front of them. This '@#@' is trimmed away after.
  2402.  
  2403. A silly example:
  2404.     #print arr[] elements with index, according to value of “sequence” string:
  2405.     #use as much variety as possible, to avoid boredom. If sequence is numeric,
  2406.     #“arrMax” holds the maximum index. 
  2407.     if (sequence == "up")#Numeric increasing index
  2408.         {
  2409.         i = 1;
  2410.         do
  2411.             {
  2412.             print i, arr[i++]
  2413.             } while (i <= arrMax);
  2414.         }
  2415.     else if (sequence == "down")#Numeric decreasing index
  2416.         {
  2417.         i = arrMax;
  2418.         while (i >= 1)
  2419.             {
  2420.             print i, arr[i]
  2421.             --i
  2422.             }
  2423.         }
  2424.     else if (sequence == "associative")#Arbitrary indexes
  2425.         {
  2426.         for (i in arr)
  2427.             {
  2428.             print i, arr[i]
  2429.             }
  2430.         }
  2431.     else
  2432.         {
  2433.         print sequence, "???!!!!"
  2434.         print "Repeat after me, ten times:"
  2435.         for (i = 1; i <= 10; ++i)
  2436.             print "I will proofread my programs."
  2437.         exit
  2438.         }
  2439.         
  2440.  
  2441. Virtually all of the sample programs in the “hAWK programs” folder illustrate
  2442. control–flow statements.
  2443.  
  2444.     Empty statements
  2445. The empty statement, which does nothing at all, is denoted by a semicolon. Loops
  2446. require a body of some sort, and if you wish no statements to be executed in the
  2447. body of the loop then just use a single semicolon for the body. More rarely, an
  2448. empty statement is useful as the statement for an “if” statement.
  2449.  
  2450. ------------------
  2451.     User-defined functions
  2452. ------------------
  2453. Functions in hAWK take the form:
  2454.     "function" name(parameter1, parameter2,...    local1, local2...)
  2455.         { 
  2456.         statements
  2457.          }
  2458. They are executed when called from within an action statement (or as part of a pattern).
  2459.  
  2460. hAWK function definitions begin with the keyword “function”, and no return type is
  2461. declared, though a value may optionally be returned. Local variables are listed after the
  2462. parameters for the function, more to simplify the grammar of the language than
  2463. anything else. Scalar parameters are passed by value (ie a local copy is made for the
  2464. function, and the original variable in the function call is not touched by the function)
  2465. whereas array parameters are passed by reference (the parameter array name refers
  2466. to the same array that is provided as the argument). Function definitions must be placed
  2467. at the top level of your program outside any pattern–action blocks, and you generally end
  2468. up with a readable program if you put all of your function definitions at the end of your
  2469. program.
  2470.  
  2471. Here’s a typical function:
  2472.         function Swap(a, i, j        temp)
  2473.             {
  2474.             temp = a[i]
  2475.             a[i] = a[j]
  2476.             a[j] = temp
  2477.             }
  2478. When called, it appears for example as
  2479.     arr[1] = 7; arr[4] = 9; Swap(arr, 1, 4)
  2480. which results in arr[1] = 9, arr[4] = 7. Note that the “temp” variable is intended for
  2481. use only within the Swap function, and is a local variable rather than a parameter of
  2482. the function.
  2483.  
  2484. Local variables are initialized to 0 and "" each time the function is called. No space should
  2485. be put between the function name and the '(' of the argument list when calling one of
  2486. your own functions, to avoid invoking the simple–minded concatenation operator.
  2487.  
  2488. Functions may return an expression, as in
  2489.     function SumArraySquared(a,        sum)
  2490.         {
  2491.         for (i in a)        #unlike C, array size need not be known separately
  2492.             sum += a[i]#note sum is local, automatically inited to zero
  2493.         return sum*sum
  2494.         }
  2495. or
  2496.     function StringUpTo(str, upto)
  2497.         {
  2498.         return substr(str, 1, index(str, upto) - 1)
  2499.         }
  2500. (eg StringUpTo("This is: a test", ":") would return "This is").
  2501.  
  2502. Some details about functions:
  2503. Newlines are optional after the left curly brace of the function body and before the
  2504. closing left brace.
  2505. Functions may call each other and may be recursive.
  2506. The word func may be used in place of function. For tired typers only.
  2507.  
  2508. -------
  2509.     Output
  2510. -------
  2511.     The “print” statement
  2512. “print” sends simply–formatted strings to a file, stdout by default. The expressions
  2513. supplied to the print statement are separated from one another by commas, and may
  2514. also be entirely surrounded by parentheses. The variations are
  2515.         print
  2516.         print expression1, expression2, ..., expressionN
  2517.         print (expression1, expression2, ..., expressionN)
  2518. A “print” with no expressions is an abbreviation for
  2519.     print $0
  2520. Each expression is converted to a string and printed in turn, with each comma being
  2521. replaced by the built–in variable OFS, by default a single blank. Each print statement
  2522. is terminated with the built–in ORS, by default a newline.
  2523.  
  2524. The parenthesized version of “print” is necessary if relational operators are present
  2525. in the expressions, since the '>' operator can mean “greater than” or “redirect output
  2526. to the file...”—see “Output into files” below.
  2527.  
  2528. The print statement is used in virtually every sample program provided, and the
  2529. more–sophisticated “printf” is seldom seen since fancy formatting is not often needed.
  2530.  
  2531. Some common print statements are
  2532.     print "" #prints just a blank line
  2533.     print names[z], FNR #documents location of something by printing file name and line
  2534. (search this file from the top for “names[z]” if you missed it)
  2535.  
  2536.     The “printf” statement
  2537. This function also has a parenthesized and unparenthesized form, 
  2538.     printf format, expression1, expression2, ..., expressionN
  2539.     printf(format, expression1, expression2, ..., expressionN)
  2540. and, as with “print”, the parentheses are needed only if a relational operator
  2541. is contained in one of the expressions. The “format” argument is interpreted
  2542. as a string, and may contain either literal text to be printed or format
  2543. specifications for strings or numbers to be printed. Format specs are indicated
  2544. in the format string by a '%', and there should be one expression following the
  2545. format for each format specification—eg if you specify that a string, a number,
  2546. and a string be printed, then you list the string, number, and string after the
  2547. format, in the same order, separated by commas.
  2548.  
  2549. The hAWK versions of the printf and sprintf functions accept the following
  2550. conversion specification formats, entirely borrowed from C:
  2551. %c        an ASCII character. If the argument used for %c is numeric, it is treated as
  2552.             a character and printed. Otherwise, the argument is assumed to be a string,
  2553.             and the only first character of that string is printed.
  2554. %d        a decimal number (the integer part).
  2555. %i        just like %d .
  2556. %e        a floating point number of the form [-]d.ddddddE[+-]dd .
  2557. %f        a floating point number of the form [-]ddd.dddddd .
  2558. %g        use e or f conversion, whichever is shorter, with nonsignificant zeros
  2559.             suppressed.
  2560. %o        an unsigned octal number (again, an integer).
  2561. %s        a character string.
  2562. %x        an unsigned hexadecimal number (an integer).
  2563. %X        like %x , but using ABCDEF instead of abcdef .
  2564. %%         a single % character; no argument is converted.
  2565.  
  2566. There are optional, additional parameters that may lie between the % and the control
  2567. letter (also from C):
  2568. -                the expression should be left justified within its field (note if the '-'
  2569.                 is absent then the expression is right justified)
  2570. width        the field should be padded to this width. If the number has a leading
  2571.                 zero, then the field will be padded with zeros. Otherwise it is padded
  2572.                 with blanks.
  2573. . prec        a number indicating the maximum width of strings or digits to the right
  2574.                 of the decimal point.
  2575. For example, %-23.14s prints strings in a field 23 characters wide, left justified,
  2576. printing at most 14 characters from the string. And %8.4f will print a floating point
  2577. number in a field 8 characters wide, right justified, with 4 digits to the right of the
  2578. decimal point.
  2579.  
  2580. The dynamic width and prec capabilities of the C library printf routines are not
  2581. supported. However, they may be simulated by using the hAWK concatenation operation
  2582. to build up a format specification dynamically.
  2583.  
  2584. Some examples:
  2585. “print var” always appends the value of ORS (by default a newline); to avoid this, use
  2586.     printf("%s ", var)
  2587. and when a newline is needed, supply one yourself with something like
  2588.     print ""        or         printf("%s\n", var).
  2589.  
  2590. Given strings of variable width in fields $1 and $2, reformat to print these strings
  2591. right–justified in two nicely–lined–up columns:
  2592.         {    one[++n] = $1
  2593.             two[n] = $2
  2594.             if (w1 < length($1))
  2595.                 w1 = length($1)
  2596.             if (w2 < length($2))
  2597.                 w2 = length($2)
  2598.  
  2599.         }
  2600.     END    {w1 += 2; w2 += 2;#a couple of spaces between columns
  2601.             for (i = 1; i <= n; ++i)
  2602.                 printf "%" w1 "s" "%" w2 "s\n", one[i], two[i]
  2603.             }
  2604. —this illustrates using the hAWK concatenation operation “to build up a format
  2605. specification dynamically”; for example, if w1 = 9 and w2 = 15 (after adding 2) then
  2606. we get
  2607.         printf "%9s%15s\n", one[i], two[i]
  2608. as the effective printf statement.
  2609.  
  2610.     Output into files
  2611. By default, “print” and “printf” send all of their output to stdout. However, the
  2612. redirection operators '>' and '>>' allow you to send output to any text file. 
  2613. Redirecting output takes one of the forms
  2614.     print expression–list > outfile
  2615.     print(expression–list) > outfile
  2616.     printf format, expression–list > outfile
  2617.     printf(format, expression–list) > outfile
  2618.     print > outfile
  2619. or any of those with '>>' instead of '>'. The '>' operator will erase the contents of outfile
  2620. before beginning to write to it, whereas '>>' will append what is being printed to outfile
  2621. without clearing the file first. Both operators open the file “outfile” the first time it
  2622. is encountered in the program, and keep it open. The file will be closed for you at the end
  2623. of your program, but if you have many files to write to you should close each output file
  2624. yourself when you are done with it, with “close(outfile)”.
  2625.  
  2626. hAWK deals with full path names only, and the names of all output files must be full path
  2627. names if you want the file to end up in a predictable place. Since hAWK is adept at
  2628. manipulating strings, and a file name is just a string, you can manufacture file names
  2629. and paths within your program to fit most needs. The built–in variable STDPATH contains
  2630. the path leading to your stdout file, so concatenating a file name to the end of STDPATH, as
  2631. in 
  2632.          outfile = STDPATH "Search Results"
  2633. will allow you to write files to the folder containing your stdout file, which is your
  2634. THINK C/Drag_on Modules folder if you followed installation suggestions. The simplest way
  2635. to concoct the appropriate path name for an arbitrary location on your hard disk(s) is
  2636. to run the hAWK program “$EchoFullPathNames”, choosing a text file in the desired
  2637. location as the input for the program. This will give you the explicit full path name, eg
  2638.     Disk:C Projects:Banana INIT:Banana source:In_your_ear.c
  2639. from which you can copy the path to use as prefix for output file names, in this case
  2640.     Disk:C Projects:Banana INIT:Banana source:
  2641. (neglect not that last colon!)
  2642.  
  2643. As special cases you can use the names "stderr" and "stdout" to redirect output
  2644. to your stderr and stdout files, eg
  2645.     print "Serious interstitial vacuities have been detected" > "stderr"
  2646. which will quietly write the message to your stderr file—you won’t be notified
  2647. that anything has been written there. Normally there isn’t much use for redirecting
  2648. output to "stdout" since it goes there anyway by default.
  2649.  
  2650. If your current input file happens to be in the right location for the output you intend to
  2651. write (for example, if the output is to be an altered version of the input, saved under a
  2652. different name) you can extract the path part of the input name, and tack it on to the 
  2653. beginning of your output file name to produce the needed full path name with this:
  2654.     BEGIN {outfile = "Results"}#a fixed name for this little example
  2655.     FNR == 1{#at the first line of the current input file
  2656.                     z = split(FILENAME, names, ":");#fragment the full path into the array “names”
  2657.                     for (i = z-1; i >= 1; --i) #note i = z gives the input file name proper
  2658.                         outfile = names[i] ":" outfile;#put path in front of outfile name
  2659.                     }
  2660.  
  2661. Can you tell what this program does?
  2662.     FNR == 1{z = split(FILENAME, names, ":");
  2663.                     outfile = names[z];
  2664.                     if (match(outfile, /[0-9]+\.[cChH]$/) > 0)
  2665.                         {#file name ends in number.c or the like
  2666.                         versNumber = substr(outfile, RSTART, RLENGTH - 2);#just the number
  2667.                         ++versNumber;
  2668.                         versNumber = versNumber ".c";
  2669.                         sub(/[0-9]+\.c$/, versNumber, outfile);
  2670.                         }
  2671.                     else
  2672.                         {
  2673.                         print FILENAME, "does not end in number dot c or h, quitting early"
  2674.                         exit
  2675.                         }
  2676.                     for (i = z-1; i >= 1; --i)
  2677.                         outfile = names[i] ":" outfile
  2678.                     }
  2679.     {print > outfile}
  2680. —among other things, it fills up your disk pretty quick. (See $TabsToSpaces.)
  2681.  
  2682.     Closing files
  2683. To close a file named by expr, use
  2684.     close(expr)
  2685. This could be a fairly explicit name, such as
  2686.     close (STDPATH "Results")
  2687. where concatenation is used to create the full name, or it could be simple
  2688.     close(outfile)
  2689. where outfile holds the string that is the full path name for the file being closed.
  2690.  
  2691. If you write to a file, then you must close it before subsequently reading from it. More
  2692. importantly, there is a limit on the number of files that can be open at once, so if your
  2693. program writes to a large or arbitrary number of files it is good policy to close each file
  2694. when it is completed. As you will see just below, it is also possible to take input from
  2695. an arbitrary file by means of redirection with the “getline” function, and in this case
  2696. as well it pays to close a file when you are done with it.
  2697.  
  2698. ------
  2699.     Input
  2700. ------
  2701.     FS, the input field separator
  2702. If you leave FS set to its default value of a single space, then any combination of
  2703. blanks and tabs will count as the field separator, and as a “bonus” any leading
  2704. blanks or tabs will be removed from the first field of each record, though they will
  2705. remain in the record itself (ie $1 is trimmed but $0 is not).
  2706.  
  2707. FS is slightly odd in that it has two modes of interpretation; when it is a single character
  2708. such as FS = ":" then the single literal character (no matter what it is) is taken as the
  2709. input field separator, but if the string for FS is longer than a single character it is
  2710. interpreted as a regular expression. Here are some commonly–used field separators:
  2711.     FS = "[ ]"    —necessary if you wish the field separator set to a single space, since
  2712.                         FS = " " invokes the default behaviour described above
  2713.     FS = "[ ,\t]+"    —any mix of blanks, commas, and tabs
  2714.     FS = "\n"    —a field is a complete line (see the discussion in the next section).
  2715.  
  2716.     RS, the input record separator
  2717. In practise RS is either left to its default value of "\n" (ie a record is the same as a line)
  2718. or can if needed be set to the null string "", in which case records are separated by one
  2719. or more blank lines. The latter corresponds to a simple form of database, with all the
  2720. lines of each record grouped together and blank lines between records. With these
  2721. multi–line records it is often useful to also set the field separator FS to "\n", so that
  2722. a field becomes a complete line.
  2723.  
  2724. Alas, these simple conceptions of a record are not often adequate. Narrative text and C
  2725. source files require a more flexible approach to input which can be generally stated as
  2726. “grab enough input to do the current job, and never mind where the lines end”. Several
  2727. solutions are discussed in the “Beyond input records” section of “Advanced
  2728. topics”—don’ t skip over the next section on “getline”, though, because it plays a
  2729. strong supporting role.
  2730.  
  2731.     The “getline” function
  2732. “getline” is a built–in function that allows you to retrieve input records from the current
  2733. input file or from any other file. As you know, the default behaviour of a hAWK program is
  2734. to retrieve input from your input files one record at a time, marching through the records
  2735. and files from beginning to end. Often, however, one needs to read in a group of lines until
  2736. some condition is met, or interrupt regular input to retrieve records from some other file,
  2737. and these are the special capabilities that “getline” provides. It can be used in the following
  2738. ways:
  2739.     getline                            sets $0 from next input record; sets NF, NR, FNR .
  2740.     getline < file                sets $0 from next record of file; sets NF .
  2741.     getline var                     sets var from next input record; sets NR, FNR .
  2742.     getline var < file            sets var from next record of file .
  2743. and in all cases “getline” returns 1 if a record was successfully retrieved, 0 if the end of file
  2744. was encountered, and -1 if some problem occurred, such as failure to find the file.
  2745.  
  2746. The effect of “getline” by itself is to dump the current string in $0 and replace it with
  2747. the next input record, setting all the usual built–in variables. Program execution then
  2748. continues with the statement following “getline”. By comparison, the “next” statement
  2749. does everything that “getline” by itself does, but in addition processing starts over
  2750. with the first pattern in your hAWK program.
  2751.  
  2752. If a variable name is present immediately after “getline”, then the input record is
  2753. retrieved to the variable instead of to $0. The '<' symbol is the input redirection
  2754. operator meaning “get input from the file...”, and is followed by the name of the input
  2755. file to use. Note that file names must be full path names, as is always the case in hAWK.
  2756.  
  2757. Some examples:
  2758. $MFS_SuperLister uses a buffer holding a variable number of lines, to match regular
  2759. expressions that can span more than one line. The heart of this program is the action
  2760.     {multi = $0;#the first line is already there
  2761.     while (getline x > 0)#== 0 at end of file, < 0 for error
  2762.         {
  2763.         multi = multi "\n" x;
  2764.         ...
  2765.         }
  2766.     }
  2767. which employs a “getline” to retrieve the contents of the current input file from the
  2768. second line to the end of the file (the first line is already present in $0). This program
  2769. is discussed further in the “Beyond input records” section of “Advanced topics”.
  2770.  
  2771. $FilesInOrderTest illustrates the technique of reading in a list of input files, then setting
  2772. up the built–in variables so that those files will be used as input for a program. In other
  2773. words, the program receives a single input file which lists the actual input files to use;
  2774. this file is read at the start of the program, and used to set up the built–in array ARGV[]
  2775. so that the program will be “fooled” into taking input from the specified list of files.
  2776. The list of files is read in at the beginning with
  2777.     BEGIN    {while (getline _specific_file_ < ARGV[1] > 0)
  2778.                 {
  2779.                 if (length(_specific_file_) > 1 &&
  2780.                 index(_specific_file_, ":") > 0)
  2781.                     ARGV[ARGC++] = _specific_file_;
  2782.                 }
  2783.             close(ARGV[1]);
  2784.             ARGV[1] = "";
  2785.             }
  2786. which reads in the full path names for the input files (one name per line) from the
  2787. first input file (ARGV[1]) into the variable “_specific_file_”. This program is
  2788. discussed further in the “Other ways of specifying input files” section of “Advanced
  2789. topics”.
  2790.  
  2791. ----------------
  2792.     The “hAWK” function
  2793. ----------------
  2794. hAWK ( arr )        : executes the hAWK program specified by the array "arr", returns
  2795. the “recursive depth” at which the call was executed. The array holds the command–line
  2796. arguments to be passed to the new program, indexed 0,1,2.... The hAWK() function is a
  2797. recursive call to hAWK itself, with all built–in variables reset to their initial values.
  2798. “hAWK” can be called anywhere a function can be called (ie in an action or function, but
  2799. not a pattern). It’s just like calling hAWK from the menu, but you don’t get a dialog
  2800. so all arguments must be explicitly supplied. If the discussion below of what to put in
  2801. "arr" seems a bit brief, see also “The command line and ARGV[]”.
  2802.  
  2803. Each call to hAWK() does chew up some memory which is not freed until
  2804. all hAWK programs terminate, so there is some finite limit on the number of times that
  2805. hAWK() can be called. In addition, memory that your program allocates by creating
  2806. arrays is not automatically freed, so if the program called by hAWK() is not the last
  2807. thing that will be done then large arrays should be “emptied out” with something like
  2808.     for (w in array)
  2809.         delete array[w]
  2810. —this memory will then be available for other programs.
  2811.  
  2812. While hAWK() can be used to sequentially execute several small programs
  2813. (see $Chain), more typically it is used to execute just one program—a program
  2814. which is specially created by the calling program to do just the task required.
  2815.  
  2816. The primary advantage offered by calling another program from within a program
  2817. is that you can select, or even create, the program to be run after doing some
  2818. preliminary analysis (reading a file or looking at the preset variables), and the
  2819. program which is eventually run will be faster than a more general–purpose one.
  2820.  
  2821. $MFS_SuperReplace for example creates a special search–and–replace program
  2822. to do the s&r you specify with your “find” and “replace” variables, in which the
  2823. regular expression to search for is an explicit string rather than the content of
  2824. a variable (ditto the replace string). The advantage is that an explicit regular
  2825. expression is analyzed only once at the start of a program, whereas a variable
  2826. (dynamic) regular expression is re–analyzed every time it is used, even if its
  2827. contents don’t change. The special–purpose program takes a moment to get going,
  2828. but then runs noticeably faster than a general–purpose search–and–replace program
  2829. which uses variables.
  2830.  
  2831. The general incantation to follow for creating the command–line array "arr" is:
  2832.     if (notFirstCall) #needed only if making more than one hAWK() call
  2833.         {
  2834.         x = 0; #arr[] is indexed 0 up - reset to 0 if making more than one call
  2835.         for (w in arr)
  2836.             delete arr[w]; #Avoid passing spurious arguments from last hAWK() call
  2837.         }
  2838.     arr[x++] = "hAWK"; #The command name in arr[0], anything you like, really.
  2839.     arr[x++] = "-f" programName; #Full path name, eg
  2840.         #progName = STDPATH "Drag_on Modules:hAWK programs:" "Type&Run program"
  2841.     arr[x++] =  "-f" FirstLibrary; #Full path name. The "-f" indicates a program name
  2842.     ...
  2843.     arr[x++] = "-f" LastLibrary;
  2844.     arr[x++] = "-v" "firstVar=" someVarfirst #Preset variables. "-v" indicates a variable
  2845.     arr[x++] = "-v" "secondVar=73"; #Value can be hard-set too
  2846.     ...
  2847.     arr[x++] = "-v" "lastVar=" lastVar
  2848.     arr[x++] = "--" #Signals only input files, if anything, follow
  2849.     arr[x++] = FirstInputFile #Full path name
  2850.     ...
  2851.     arr[x++] = LastInputFile
  2852.     notFirstCall = 1; #Needed only if making more than one call to hAWK()
  2853.     depth = hAWK(arr); #invoke the program; returned value can be ignored.
  2854. If you wish to pass all input files along to the program being called, use
  2855.     for (j = 1; j < ARGC; ++j)
  2856.         arr[x++] = ARGV[j]
  2857. If you wish to use stdout as the input, use
  2858.     arr[x++] = STDPATH "$tempStdOut"
  2859. For some real examples, see $Chain, $Type&Run, $RunClip, and $MFS_SuperReplace.
  2860.  
  2861. Note that no argument count “argc” needs to be passed to the hAWK() call; internally,
  2862. the end of arguments is detected by looking for 10 consecutive null arguments (eg if
  2863. arr[8] is non-null and arr[9] through [18] = "", then arr[8] is taken as the last
  2864. real argument).
  2865.  
  2866. A small bonus; when calling a hAWK program through the main dialog interface you
  2867. are limited to presetting at most 10 variables, but when using the hAWK() function
  2868. there is no limit on the number of variables you can preset.
  2869.  
  2870. -------------
  2871.     Advanced topics
  2872. -------------
  2873. “Advanced” is a bit pompous, really—you should have read through the above
  2874. material, tried out some of the supplied programs, and written a couple of
  2875. small programs yourself by this point. That’s all “advanced” means. And the
  2876. last section, “Calling hAWK through Minimal App”, is advanced only in terms
  2877. of understanding what’s going on behind the scenes. The instructions themselves
  2878. are easy to follow. 
  2879.  
  2880.     Other ways of specifying input
  2881. For use when you need to run a hAWK program on several input files with the files
  2882. taken in some specific order, or if you need to hard–code the name of an input file into a
  2883. program, and intend to process the contents of that file before or after all other
  2884. input files.
  2885.  
  2886. The way to persuade a hAWK program to treat input files in a specific order is to
  2887. prepare the list of files in the order required, and then modify the program to use
  2888. that list as the names of the input files. This requires building the list, and a small
  2889. addition to the program itself, but it’s not hard to do:
  2890. 1 If possible, use your calling application to select the files for multi–file operations
  2891. (“searching”), and then run the hAWK program “$EchoFullPathNames”. hAWK uses
  2892. full path names to specify files, and this program will produce a list of the full path
  2893. names for the files you selected, in the window called “$tempStdOut”. You can
  2894. painfully construct full path names for your files by hand, but using this hAWK
  2895. program is the simpler way.
  2896. 2    Arrange the full path names into your desired order, and if it’s a list you anticipate
  2897. using again, use “Save As” to save the list away permanently (the contents of
  2898. $tempStdOut don’t survive from one run to the next).
  2899. 3    Copy this block of code to the top of your hAWK program, before all other code:
  2900.         BEGIN    {while (getline _specific_file_ < ARGV[1] > 0)
  2901.                     {
  2902.                     if (length(_specific_file_) > 1 && index(_specific_file_, ":") > 0)
  2903.                         ARGV[ARGC++] = _specific_file_;
  2904.                     }
  2905.                 close(ARGV[1]);
  2906.                 ARGV[1] = "";
  2907.                 }#end
  2908. This is executed before the rest of your program, and transparently converts the list of
  2909. input files in the array ARGV[] to the list provided in the one input file “ARGV[1]”
  2910. that is actually supplied when running it. The name of that one orginal input file is
  2911. nulled out, which persuades hAWK to ignore it when input processing starts for real.
  2912. 4    When calling the hAWK program, select your list of files as the only input. If the
  2913. list is in the front window, pick “All of front text”, if it’s in a file use the
  2914. “Select input file…” option to select the file. Then run the program.
  2915.  
  2916. If you want to try this out in a test program, read through “$FilesInOrderTest”,
  2917. then run it and pass it a list of files. It will just print the list of files to $tempStdOut,
  2918. confirming that they were read in the correct order.
  2919.  
  2920. If you want your program to take input from some specific file first, and then take
  2921. input from whatever files are provided via the setup dialog, then you can pass your
  2922. program the name of the specific file by means of a variable and process the file in a
  2923. BEGIN block. Once again, the only real difficulty is to determine the full path name of
  2924. the file, and this can be done by using $EchoFullPathNames as described above, but
  2925. passing it the single file as input.
  2926. The method in full is:
  2927. 1    Determine the full path name of the specific file, eg
  2928.         Hard Disk:Top Folder:Bottom folder:theFile
  2929. 2    Do the processing of this specific file in the BEGIN block of your program, in
  2930. the following way:
  2931.             BEGIN     {    while (getline _x < _specific_file_ > 0)
  2932.                                 {
  2933.                                 -process _x, which contains the lines of _specific_file_
  2934.                                 }
  2935.                         close(_specific_file_)
  2936.                         - optional other statements in your BEGIN block
  2937.                         }
  2938. 3    While setting up your program for a run, use “Set variables” to provide the
  2939. full path name of the specific file in the variable _specific_file_:
  2940.             _specific_file_=Hard Disk:Top Folder:Bottom folder:theFile
  2941. and then click “Save settings” if you will be using this file name more than once.
  2942. 4    Run your program, using the setup dialog to take input from wherever is
  2943. appropriate. For an example, see “$WordFrequency”.
  2944.  
  2945. If you want to process a special file after all regular input, then use the same
  2946. structure as in point 2 above, but in an END block rather than a BEGIN block.
  2947.  
  2948. If the specific file is to be treated in exactly the same way as your other input files,
  2949. but must be processed first, then you can add this BEGIN block to the start of your
  2950. program, again using a fixed full path name passed in the variable “_specific_file_”:
  2951.     BEGIN    {    for (i = ARGC; i >= 2; --i)#Note this creates ARGV[ARGC]
  2952.                         ARGV[i] = ARGV[i-1];
  2953.                     ARGV[1] = _specific_file_;
  2954.                     ARGC++;
  2955.                 }
  2956.  
  2957. Appending a specific input file is even easier, just
  2958.     BEGIN    {    ARGV[ARGC++] = _specific_file_; }
  2959.  
  2960. You may find these techniques useful if your program needs a list of “data” before
  2961. running, in other words too much information to fit in the ten variables that you
  2962. can preset before each run.
  2963.  
  2964. The built–in variable STDPATH is a path name which specifies the folder that holds,
  2965. among other things, your “Drag_on Modules” folder, which in turn holds your “hAWK
  2966. programs” folder. If your specific input file is in the “hAWK programs” folder for
  2967. example, then you can avoid spelling out the full path name by using “Set variables” to
  2968. set “_specific_file_” to just the name of the file, eg
  2969.     _specific_file_=Initial data file
  2970. and then before using _specific_file_ insert the line
  2971.     _specific_file_ = STDPATH "Drag_on Modules:hAWK programs:" _specific_file_;
  2972. to build up the full path name for _specific_file_.
  2973.  
  2974. The above two methods can be blended together, for example to process an entire
  2975. list of files before dealing with other input files provided by the setup dialog, and
  2976. the files could be processed just as easily in an END block as in a BEGIN block.
  2977.  
  2978.     Beyond input records
  2979. Let’s face it, not many text files are organized into neat lines or even groups of lines,
  2980. so it is often more appropriate to use hAWK’s automated record retrieval as just the
  2981. first stage of input, building functions on top of it to extract the precise input for the
  2982. job at hand. Four techniques are discussed below: “control–break”, which keeps track
  2983. of current input status by means of variables; “input on demand”, which buries the
  2984. problem of getting the next piece of input in a single function; end–buffered input,
  2985. which, if it reads in too much, temporarily stores the excess input to one side; and a
  2986. rolling buffer, which acts as a multiple–line “window” on the input, the number of
  2987. lines being variable at whim.
  2988.  
  2989. The “control–break” style of reading input wrestles with the problem that
  2990. you don’t know you’ve read in too much input until you’ve read in too much—what to
  2991. do then? The general solution is to use variables to keep track of what the current
  2992. “state” is (typically the states are “more input wanted” and “oops, a bit too much”).
  2993. This leads to control constructs which seem to put the cart before the horse, in that
  2994. one first takes action based on the value of a variable, and only later in the program is
  2995. the variable set, which requires a bit of planning.
  2996.  
  2997. As a simple illustration,
  2998.     $1 != lastFieldOne    { print "New field one is", $1
  2999.                                         lastFieldOne = $1
  3000.                                     }
  3001. which has been seen before, prints the contents of the first field on the input line
  3002. whenever it changes. The variable “lastFieldOne” is used to control output.
  3003.  
  3004. The general approach with control–breaks is, in pseudo–language:
  3005.     if (toofar)
  3006.         scramble to catch up;
  3007.     else
  3008.         proceed normally;
  3009.     set the toofar variable;
  3010.  
  3011. At this point, you might want to read through an example of control–breaks: $XRef
  3012. deals with the problem of skipping over comments and strings in C code, even though
  3013. hAWK reads the input one line at a time and comments and strings can be anywhere.
  3014.  
  3015. “Input on demand” is a way of using “getline” in combination with formatting functions
  3016. to retrieve input sequentially as though the entire file were one large record, without
  3017. cluttering up the top level of your program. The details of translating from line
  3018. format to your required format are buried in a function that keeps track of the
  3019. relation between the two; once this function is written, the top level of your
  3020. program can call this function without worrying about the translation details.
  3021.  
  3022. For a full example, see $Print_MENU_Resource, which deals with the problem of
  3023. reading and formatting a MENU resource, as retrieved by Read Resource.
  3024.  
  3025. End–buffered input relies on retrieving input lines through two functions,
  3026. “GetNextLine” and “UngetLine”, and a variable “inBuffer” which keeps track of
  3027. whether a line was “ungot”. With this approach there is no need to “scramble to catch
  3028. up”, since the extra input is stored to one side until the next “GetNextLine” call. The
  3029. conditions under which a line is to be stored due to going too far depend on the context
  3030. (ie it’s up to you), but the general approach is
  3031.     function DoTheJob(file,            line)
  3032.         {    getError = 1;
  3033.         while (GetNextLine(file, line) > 0)
  3034.             {
  3035.             if (you decide that’s too far)
  3036.                 UngetLine(line);
  3037.             else
  3038.                 process line;
  3039.             }
  3040.         }
  3041. and the functions that get and unget are
  3042.     function GetNextLine(file, line)
  3043.         {
  3044.         if (getError <= 0)
  3045.             return getError;
  3046.         if (inBuffer)
  3047.             {
  3048.             line = _buffer;
  3049.             inBuffer = 0;
  3050.             return 1
  3051.             }
  3052.         return getError = (getline line < file)
  3053.         }
  3054.     
  3055.     function UngetLine(line)
  3056.         {
  3057.         _buffer = line
  3058.         inBuffer = 1
  3059.         }
  3060. where “file” is the full path name of the file to take input from.
  3061.  
  3062. For an example using end–buffered input, see “The AWK programming language” by
  3063. Aho, Kernighan, and Weinberger, page 105. You’ll find this approach useful if you
  3064. have small databases to analyse.
  3065.  
  3066. The rolling–buffer approach to input adds lines of input to the end of a variable, and
  3067. removes them from the front. The variable in question can contain more or fewer lines
  3068. according to the needs of the moment, though there should be an upper limit on the number
  3069. of lines. In pseudo–language, the general approach to rolling lines of input through a
  3070. buffer variable is:
  3071.     while (getline x > 0)
  3072.         {
  3073.         multi = multi "\n" x;#add current line x to end of buffer variable “multi”
  3074.         process multi however you like;
  3075.         while (too many lines in multi)
  3076.             {
  3077.             j = index(multi, "\n");#position of first newline in multi
  3078.             #first line in multi, if needed, = substr(multi, 1, j);
  3079.             multi = substr(multi, j + 1);#trim first line from multi
  3080.             }
  3081.         }
  3082. The “while (getline x > 0)” loop stops normally when the end of the current input file
  3083. is reached (abnormal, as in file missing, is possible but unlikely). You can count
  3084. the number of lines in multi at any time with
  3085.     numMultiLines = gsub("\n", "\n", multi)
  3086. which replaces newlines with newlines, and relies on gsub returning the number of
  3087. replacements—awkward, but it works. Arbitrary chunks of text can be removed from
  3088. the front of multi if desired, rather than removing a line at a time.
  3089.  
  3090. For a full and very useful example see “$MFS_SuperLister” which is capable
  3091. of matching a regular expression or string of text even if it spans a variable number
  3092. of lines. “$MFS_SuperReplace” is similar, doing multi–file search and replace instead
  3093. of just listing matches.
  3094.  
  3095.     Calling hAWK through Minimal App
  3096. Minimal App does not support passing text or file lists to hAWK, or showing results
  3097. after a run, but these things can be done with a bit of extra work on your part. If
  3098. you’re not interested in using Minimal App or some other application that provides
  3099. minimal support for hAWK as your main hAWK–caller, you can skip this section.
  3100.  
  3101. Since Minimal App does not support text documents at all, you’ll need an editor of some
  3102. sort in order to do these things, and the assumption here will be that you’re running
  3103. under MultiFinder (or system 7), using your favourite editor. You could also use a
  3104. Desk Accessory editor together with Minimal App, a practical alternative if you intend
  3105. to do nothing but run hAWK programs for an extended period. However, the focus here is
  3106. on running hAWK programs while using an editor that does not support calling hAWK,
  3107. by using Minimal App, MultiFinder, and a few workarounds.
  3108.  
  3109. Ideally, an editor designed to run under MultiFinder should offer you protection against
  3110. creating multiple versions of a file, and provide some automatic means of ensuring that
  3111. you are always viewing the most up-to-date version of a file. An adequate solution in a
  3112. single–user context would be for all editors to cooperate by offering the options of
  3113. automatically saving all open files when switching out, and refreshing all open files
  3114. from disk (if necessary) when switching back. At present almost all Macintosh editors
  3115. are, in this sense, MultiFinder–unaware. So unless you know otherwise, it’s up to you
  3116. to ensure that you keep the screen and disk versions of a file synchronised by Saving and
  3117. Reverting with your editor at the appropriate times, as described below. Nuisance, what?
  3118.  
  3119. First, let’s look at passing all or part of a file to hAWK, and viewing the result of a run.
  3120. Since hAWK provides as your input option just the ability to select a single file when
  3121. called through Minimal App, the simplest approach is to use a single common file as the
  3122. input file for all programs which expect input from all or part of a file, and use the
  3123. setup dialog to set (and save) that file as the input file. Oddly, the simplest file to pick
  3124. is stdout ($tempStdOut, in the same folder that holds Minimal App). There is no
  3125. conflict between passing stdout to a program as input, and then writing to stdout,
  3126. because just before your program is run hAWK will rename your stdout file to
  3127. “$tempOutAsInput” and then pass that name to your program. The “old” version
  3128. of stdout will be used as input, and the “new” version will hold whatever was written
  3129. to stdout during the run. With stdout as your common input file, the approach to use
  3130. for passing all or part of a file from your editor to a hAWK program is:
  3131. • Open the stdout file (ie $tempStdOut) in your editor, and leave it open (you can create
  3132. this file by running $EnumSwitch with no input, or create it with your editor - it goes
  3133. in the same folder as Minimal App and the Drag_on Modules folder, at the same level)
  3134. • Copy/Paste the input text over all of stdout, and Save it.
  3135. • Switch to Minimal App, call up hAWK, and select your program.
  3136. • If it’s the very first run, use the “Select input file...” command to select $tempStdOut
  3137. as the specific input file, and then Save Settings so the program will remember this.
  3138. • Run the program.
  3139. •Return to your editor, type a character in the stdout window, and Revert - you’ll see
  3140. what was written to stdout by the program. To view any other created or altered files,
  3141. you’ll need to open them with your editor.
  3142.  
  3143. Here’s an example run, to get you going. The example program is $EnumSwitch, which
  3144. takes a list of enum constants and generates a “switch” statement based on them. You
  3145. should be viewing this file with your editor, and also have Minimal App up and running
  3146. in a separate partition under MultiFinder or system 7 at some point.
  3147. • Copy the indented line just below with your editor, and Save it as the entire contents
  3148. of $tempStdOut, in the same folder where you’re keeping Minimal App.
  3149.         {first, second, third, fourth, twilightZone = -99}
  3150. • Leave the $tempStdOut file open.
  3151. • Switch to Minimal App and select hAWK; use the “Main program:” popup menu
  3152. to select “$EnumSwitch” as the program to run.
  3153. • Use the “Select input file...” option under the “Take input from:” popup menu
  3154. to select your “$tempStdOut” file as the input file to use with $EnumSwitch.
  3155. • Click the “Save settings” button so that $EnumSwitch will remember which
  3156. input file to use for subsequent runs.
  3157. • Click the Run button, and wait until the highlighting goes away from the main
  3158. menu bar, signalling that the program is done.
  3159. • Return to your editor, type a character in the $tempStdOut window, and pick
  3160. Revert; you’ll see the results of $EnumSwitch on the line of enums you started with.
  3161.  
  3162. Some programs, such as $MFS_SuperReplace, naturally work with a list of files rather
  3163. than just a single file. Here the simplest approach is to pass to your program a single
  3164. input file which contains a list of the actual files to use as input. Again, it is best to
  3165. settle on a single name for the file which contains the file list, and use the setup dialog
  3166. to set the program to take input from this file. Here the name doesn’t matter, and 
  3167. something like “Standard File List” would do ($tempStdOut and other standard files
  3168. are best avoided here). It then remains to; create the list of files, and internally alter
  3169. the program(s) so that they will properly interpret the file list.
  3170.  
  3171. First, the list of files: it should be a list of full path names, one file per line. You can
  3172. generate the full path name for any single file by running “$EchoFullPathNames” with
  3173. the file in question as input. Given that path, you can then generate full path names for
  3174. other files in the same folder with a bit of copying and replacing of the file name,
  3175. leaving the path the same. Some editors can generate full path names for files, which is
  3176. an easier approach. If you have no easy way of generating full path names you might
  3177. want to create a “master list” of full path names, and selectively copy the needed names
  3178. to your “Standard File List” file before running a hAWK program.
  3179.  
  3180. Each program that you want to take input from your file list needs a small addition
  3181. at the beginning. Open the program, and copy the following BEGIN block into the
  3182. program, as the very first block of code in the file:
  3183.     BEGIN    {while (getline _specific_file_ < ARGV[1] > 0)
  3184.                 {
  3185.                 if (length(_specific_file_) > 1 && index(_specific_file_, ":") > 0)
  3186.                     ARGV[ARGC++] = _specific_file_;
  3187.                 }
  3188.             close(ARGV[1]);
  3189.             ARGV[1] = "";
  3190.             }#end addition
  3191. This persuades the program to take input from the list of files, rather than treating
  3192. the list of files as the input. This may look familiar, as it’s the same alteration
  3193. described in the first section of this chapter for persuading a program to take input
  3194. from a list of files in specific order.
  3195.  
  3196. And finally, to run a hAWK program on a list of files:
  3197. • Your “Standard File List” file should contain the exact list of files that you want to
  3198. use as input files, as full path names. Remember to Save it if you change it, before
  3199. running your program.
  3200. • Switch to Minimal App, call up hAWK, and select the program to be run. 
  3201. • If it’s the very first run, use the “Select input file...” command to select your file
  3202. containing the file list as the specific input file, and then Save Settings so the program
  3203. will remember this.
  3204. • Run the program.
  3205. • Back to your editor, and Revert stdout as described above if the program writes to
  3206. stdout.
  3207.  
  3208.  
  3209. ---------------------------
  3210.     Calling hAWK from your application
  3211. ---------------------------
  3212.     What and how
  3213. Your application, that is, any application for which you have the source code, should
  3214. be a THINK C project. If your application is written for some other C compiler, you
  3215. should be able to modify the supplied source without too much anguish. If your application
  3216. is not written in C you will still be able to call hAWK if your language supports calling
  3217. C–style functions. However, you will have to provide your own equivalent for the
  3218. file “Call_Resource.c”, not a trivial undertaking. The following discussion
  3219. will assume that your application is built from a THINK C project.
  3220.  
  3221. Drag_on Modules, of which hAWK is an example, are CODE resources. To call a
  3222. Drag_on Module, you load the first segment of its code (CODE 0), set up a pointer
  3223. to an interface structure which contains file names and “callback” functions, and
  3224. then jump to the starting address of the CODE resource as though it were a C–style
  3225. function. Your application will load a list of Drag_on Modules into a menu for selection
  3226. by the user.
  3227.  
  3228. Modifying your application to call hAWK and other Drag_on Modules divides into two
  3229. stages: adding the source file “Call_Resource.c” to your project and inserting two
  3230. function calls in your source; and then, when the basic version has checked out,
  3231. deciding what level of support to supply for callback and result–showing functions.
  3232.  
  3233. Drag_on Modules can be called by virtually any application, but considerable enhancement
  3234. is possible if your application supports text windows and files. For example, hAWK can
  3235. take input from the front text window of your application, and relies on your application
  3236. to show the text file stdout if the user requests it. If your application doesn’t support text
  3237. windows and files it can still call hAWK, but some input options and the showing of
  3238. result files will be absent.
  3239.  
  3240.  
  3241.     Getting started
  3242. To get going, add the source file “Call_Resource.c”, in the “code to call Drag_ons”
  3243. folder on the same disk where you found this manual, to your application project. You
  3244. will also need to add the standard ANSI library if it’s not already in your project (this
  3245. won’t add much to the size of your built application). Compile it, and run it as well to
  3246. check for linkage errors. If your application lacks some of the toolbox headers that are
  3247. normally included in the MacHeaders precompiled standard header then you may have to
  3248. explicitly #include them in the file “Call_Resource.c”.
  3249.  
  3250.     Add two calls in your code
  3251. First, decide which of your application menus to use for showing the Drag_on Modules.
  3252. Then follow the instructions at the top of “Call_Resource.c” in points 2 and 3 which
  3253. describe how and where to place the two calls to functions in “Call_Resource.c”.
  3254. InitCallResources() will load a list of Drag_on Modules into your chosen menu, and
  3255. CallResource() will call a Drag_on Module when it is selected from your menu.
  3256.  
  3257. For an example of adding “Call_Resource.c” to an application and inserting the two
  3258. required function calls, see the source code and THINK C project for “Minimal App”
  3259. (the two calls are in “minimalApp.c”, and the copy of “Call_Resource.c” in the
  3260. “Minimal App” folder is identical to the original in “code to call Drag_ons”).
  3261.  
  3262.     A minimal version
  3263. Verify that line 98 or so of “Call_Resource.c” reads
  3264.     #define SUPPORT_LEVEL MINIMAL
  3265. Bring your THINK C project up to date, and build a new version of your application. In
  3266. order for hAWK and company to show up in your menu, the folder “Drag_on Modules”
  3267. (with hAWK inside) needs to be in the same folder as your application, at the same
  3268. level, so do this first before starting up your application.
  3269.  
  3270. Start your application, and you should see hAWK  listed under the menu you have chosen
  3271. to show Drag_on Modules. Select hAWK, and the setup dialog should appear; however,
  3272. input options under the “Take input from:” popup will be limited to just the
  3273. “Specific input file...” option. Select the program “$EchoFileNames”, and then use
  3274. the “Take input from:” option to select any TEXT file for it to use as input. Click
  3275. Run, wait about 2 seconds or until the mouse is back under your control, and then
  3276. check however you like that the file “$tempStdOut” contains the name of the file you
  3277. selected as input for “$EchoFileNames”.
  3278.  
  3279.     Callbacks, and showing results
  3280. Once you have the above basic version up and running, you should read through the
  3281. “Call_Resource.c” file and decide how much support to provide for the tasks of
  3282. offering input options and showing the “$tempStdOut” result file. An important
  3283. and easily–supported alert function (OKStopAlert) and a function for changing the
  3284. cursor to a watch round out the list of functions that enhance hAWK’s
  3285. performance (or any Drag_on Module, for that matter). The more functions
  3286. you support, the more useful hAWK will be to your users.
  3287.  
  3288. If you decide to support any of these optional capabilities, also change the
  3289.     #define SUPPORT_LEVEL MINIMAL
  3290. statement in “Call_Resource.c” to reflect the level of support you are providing
  3291. (instructions for this are in the file, around line 86).
  3292.  
  3293. Finally, around line >=131 in “Call_Resource.c” you will see the statement
  3294.     static char callerName[] = "MyApp";
  3295. Change the name to the name of your application, and you’re done.
  3296.  
  3297. Any enhancements or modifications you make are your own business. However, hAWK
  3298. and most of the source code for hAWK is copyright by the Free Software
  3299. Foundation—you can distribute hAWK and the source code for it, provided you follow the
  3300. restrictions contained in the file “COPYING hAWK”, on the same disk where you found this
  3301. manual. Where Dynabyte (Ken Earle) might be construed as owning the copyright, all rights are
  3302. waived except the right to copyright, this latter only to preserve the former. Catch 23.
  3303.  
  3304.     Using a command line
  3305. The last parameter to CallResource() is a pointer to an optional text command line. If
  3306. this is not NULL, then the command line will be used to invoke the program specified by
  3307. the command line, with no dialog shown. There are two things to do to make this work
  3308. with your application:
  3309. • construct a proper command line for hAWK
  3310. • put something in your user interface to let your users call hAWK with the command line.
  3311.  
  3312. This is the format of a hAWK command line (note it can cover several lines):
  3313.  
  3314. hAWK -f"Program Name" -f"Library Name"
  3315.     -s -ss -n
  3316.     -vVariableName="some value" -- MFS "InputFullPathname"
  3317.  
  3318. • the entire command line should be a C string (null terminated)
  3319. • the command line text must begin with "hAWK" followed by a space or tab
  3320. • there must be one program name, as signalled by -f. If you just supply a simple program name,
  3321. it must reside in the "hAWK programs" folder. Use a full path name if the program is in some other
  3322. folder. If the program name (or any part of the full path name) contains a space, then put quotes ""
  3323. around the full name, otherwise the quotes are not needed.
  3324. • the library names are the same as program name, and these are optional. Since library names
  3325. look the same as the program name, the first one seen is taken as the program name.
  3326. • variables are signalled by the -v option, eg -vmyName="Ken E" or -vlevel=1
  3327. where the quotes "" are optional if the value contains no spaces or tabs. Spaces before the '=' sign
  3328. are optional, but don't put any between the '=' and the actual value. Variables are optional. In
  3329. particular, any variable settings that have been saved with the program (by using the setup
  3330. dialog) will automatically be passed along with the command line, and so you should set these
  3331. variables on the command line only if you want to override the default saved values (to see
  3332. those, select the program in the setup dialog and click the "Set variables..." button).
  3333. • "--" signals that input files only follow. This is optional, mainly to make reading easier.
  3334. • "MFS" stands for "all files currently selected for multi-file operations", an input option
  3335. that must be implemented by the calling application. This one is optional.
  3336. • input file names are optional, and should be provided as full path names. If any part of the full
  3337. name contains a space then the quotes "" are necessary, otherwise they're optional.
  3338.  
  3339. You may also optionally use the following output options in the command line (place them before
  3340. any "--"):
  3341. • -s means show stdout when done
  3342. • -ss means show and select stdout when done
  3343. • -n means no showing of stdout when done.
  3344.  
  3345. If you don't provide an output option, any output option from the settings saved with the program
  3346. will be used instead (these correspond to the "Show/select stdout" checkboxes in the setup dialog).
  3347. Any output option you do provide overrides the saved settings.
  3348.  
  3349. You may supply both "MFS" and one or more specific input files on a command line, and unlike the
  3350. dialog approach you may supply any number of variables (the dialog is limited to 10).
  3351.  
  3352. As far as the interface goes, pressing <enter> or <command><return> to fire off a command line
  3353. is reasonably standard (you may also require the entire command line to be selected, depending
  3354. on how confusing things would be otherwise). 
  3355.  
  3356. Some example command lines:
  3357.  
  3358. hAWK -f$EchoFullPathNames -- MFS
  3359.  
  3360. hAWK -f$BoilerPlate -vputInComment=1 -vfile="@.c" -vauthor="KE" -vcompany="bdibdi" -ss
  3361.  
  3362. -------------
  3363.     Modifying hAWK
  3364. -------------
  3365.     Introduction
  3366. Building hAWK used to be a nontrivial undertaking. Now, just build the "hAWK.µ" CodeWarrior
  3367. project, merging it into an existing copy of "hAWK" when the merge dialog appears.
  3368. At present, CodeWarrior ANSI libraries suffer from the problem that they allocate
  3369. a 65K pointer and never let go of it, but this is worked around by throwing hAWK
  3370. into its own heap zone when calling it, then dumping the whole heap when done.
  3371.  
  3372. Warning: the original PC code that hAWK is based on is old, very old,
  3373. and the modifications to make it Macintosh were rather brutally done. If you plan
  3374. major changes to hAWK, expect some grief along the way.
  3375.  
  3376. END hAWK MANUAL
  3377. (OOPS forgot to provide the Reverse Polish expression interpreter - what a tragedy...)
  3378.  
  3379.  
  3380. -------------------
  3381.     Active index
  3382. -------------------
  3383. This index lists line numbers for topics, suitable for use with editors that
  3384. allow you to jump to or “Go to” a selected line number
  3385.  
  3386. | in reg. exp. 1680
  3387. || in patterns 1857
  3388. ~ (matching operator) 1600
  3389. ~! (not match operator) 1639
  3390. π 2100
  3391. \ in reg. exp. 1680
  3392. \1...\9 1706
  3393. \< 1692
  3394. \> 1693
  3395. \B 1695
  3396. \b 1694
  3397. \n 1697
  3398. \t 1696
  3399. \W 1691
  3400. \w 1690
  3401. ! in patterns 1857
  3402. $about the supplied programs 839
  3403. $tempStdIn 564 740
  3404. $tempStdErr 740
  3405. $tempStdOut 692 740 752
  3406. $tempStdOut is temporary 774
  3407. $ to start program name 525
  3408. $ in reg. exp. 1680
  3409. $EnumSwitch 401 1041
  3410. $FilesInOrderTest 2771
  3411. $MFS_SuperLister 2758
  3412. $PatternTester 1926
  3413. $sample programs see 839
  3414. && in patterns 1857
  3415. ( ) in reg. exp. 1680
  3416. * in reg. exp. 1680
  3417. + in reg. exp. 1680
  3418. . in reg. exp. 1680
  3419. >, >> (redirection) 2610
  3420. ? : in patterns 1873
  3421. ? in reg. exp. 1680
  3422. [ ] in reg. exp. 1680
  3423. ^ in reg. exp. 1680
  3424. actions 1947
  3425. All of front text 561
  3426. ANSI a4 3334
  3427. ARGC 1157 1325
  3428. ARGV[] 1147 1325
  3429. arrays 1439
  3430. atan2() 2082
  3431. automatic conversion 1405
  3432. auto version incrementing 2661
  3433. AWK and GAWK 268
  3434. backslash to break long lines 1098
  3435. beep() 2202
  3436. BEGIN (pattern) 1556
  3437. break 2351
  3438. breaking lines 1090
  3439. built–in string and file functions 2109
  3440. built–in variables 1325
  3441. built–in numeric functions 2082
  3442. Call_Resource.c 3242
  3443. calling hAWK from your application 3210
  3444. cancelling a run 735
  3445. close() 2682
  3446. command line 1147
  3447. comments in the source 1013 1115
  3448. comparison operators in patterns 1586
  3449. compound patterns 1856
  3450. concurrent and immediate modes 460
  3451. continue 2355
  3452. control–break 2989
  3453. control-flow statements 2311
  3454. concatenation 2010
  3455. constants 1247
  3456. conversion, numbers and strings 1405
  3457. copy() 2204
  3458. cos() 2082
  3459. delete 1472
  3460. do-while statement 2333
  3461. empty statements 2444
  3462. END (pattern) 1556
  3463. end–buffered input 3025
  3464. example hAWK programs 839
  3465. exists 2214
  3466. exit 2364
  3467. exp() 2082
  3468. expression operators 2024
  3469. expressions (as patterns) 1576
  3470. expressions in actions 1967
  3471. fields ($1 $2 etc) 1028 1280
  3472. fdate() 2216
  3473. FILENAME 1325
  3474. files, closing 2682
  3475. FNR 1325
  3476. for (var in array) 1471 2348
  3477. for (;;) statement 2338
  3478. Front text selection 560
  3479. FS (field separator) 1292 1325 2701
  3480. fsize() 2221
  3481. full path name, splitting 1543 2656
  3482. full path names 1222 1366 1545 2626
  3483. functions, user–defined 2451
  3484. function, local variables 1374
  3485. GAWK and AWK 260
  3486. getclip() 2222
  3487. getline 2731
  3488. grouping and breaking lines 1090
  3489. gsub() 2109
  3490. hAWK programs (folder) 525
  3491. hAWK, calling from your application 3210
  3492. hAWK, installing 191
  3493. hAWK() function 2792
  3494. if statement 2324
  3495. IGNORECASE 1325
  3496. immediate and concurrent modes 460
  3497. int() 2082
  3498. in (operator) 1459
  3499. index() 2109
  3500. input files, in order 2886
  3501. input on demand 3015
  3502. input selection for a program 536
  3503. installing hAWK 191
  3504. length() 2109
  3505. library files 666
  3506. lines, breaking and grouping 1090
  3507. list() 2234
  3508. local variables 1374 2484
  3509. log() 2082
  3510. lookup() 2141
  3511. Main program: (popup) 525
  3512. match() 2109
  3513. metacharacters 1680
  3514. MFS selected files 570
  3515. Minimal App 3258
  3516. minimalApp.c 3259
  3517. missing pattern 1537
  3518. modifying hAWK 3305
  3519. multiline records 2718
  3520. name conventions for programs 525
  3521. nested() 2239
  3522. next 2360
  3523. NF 1325
  3524. no input, specifying 590
  3525. NR 1325
  3526. null string 1267
  3527. number versus string 1405
  3528. numeric functions, built–in 2082
  3529. octal in reg. exp. 1713
  3530. OFMT 1325
  3531. OFS 1325
  3532. tolower() 2109
  3533. operators, table of 2033
  3534. ordering input files 2886
  3535. ORS 1325
  3536. output into files 2610
  3537. patterns and actions 1527
  3538. path names 1222 1366 1545 2626
  3539. patterns 1525
  3540. pattern, missing 1537
  3541. patterns, summary 1905
  3542. pipes (none) 287
  3543. presetting variables 598
  3544. print (preview of) 1990
  3545. print (details) 2511
  3546. printf statement 2536
  3547. printing this manual 232
  3548. program name conventions 525
  3549. program, input selection 536
  3550. prompt() 2174
  3551. punctuation, inside / / 1623
  3552. punctuation, inside quotes 1630
  3553. putclip() 2228
  3554. rand() 2082
  3555. range patterns 1881
  3556. records ($0) 1028 1280
  3557. redirecting output 2610
  3558. references 244
  3559. regular expressions 1644
  3560. regular expressions, examples 1752
  3561. remove() 2247
  3562. rename() 2251
  3563. return 2460
  3564. RLENGTH 1325
  3565. rolling buffer for input 3066
  3566. RS (record separator) 1325 1285
  3567. RSTART 1325
  3568. Run button 452 727
  3569. RUNERR 1325
  3570. sample hAWK programs 839
  3571. Save settings (button) 711
  3572. setup dialog 430
  3573. setup, saving 711
  3574. setting variables before a run 598 1225 1394
  3575. Selecting input for a program 536
  3576. Select all of stdout (checkbox) 706
  3577. Select input file… 582
  3578. Select unlisted program… 528
  3579. Show stdout (checkbox) 699
  3580. sin() 2082
  3581. sort() 2156
  3582. SortLibrary, sample library 685
  3583. specific order for input files 2886
  3584. split() 2109
  3585. split full path name 1543 2656
  3586. sprintf() (see also printf) 2549 2109
  3587. sqrt() 2082
  3588. srand() 2082
  3589. STDPATH 1325 2632 2964
  3590. standard input and output 740
  3591. statement grouping with {} 2321
  3592. stderr 2643
  3593. stdout 2643
  3594. string functions, built–in 2109
  3595. string-matching patterns 1600
  3596. string versus number 1405
  3597. sub() 2109
  3598. substr() 2109
  3599. SUBSEP 1325 1451
  3600. summary of patterns 1905
  3601. supplied hAWK programs 839
  3602. system 289
  3603. Take input from: (popup) 560
  3604. TIME builtin variable 1372
  3605. time() 2170
  3606. toupper() 2109
  3607. uninitialized variables 1267
  3608. unix a4 library 3334
  3609. user-defined functions 2451
  3610. variables 1247
  3611. variable, setting before a run 598 1225 1394
  3612. version incrementing 2661 (see also $TabsToSpaces)
  3613. while statement 2327
  3614.